- 浏览: 202870 次
- 性别:
- 来自: 北京
文章分类
最新评论
-
moonskyii:
基于flex 和red5的视频聊天 -
yilinhust:
abc.html中有相关字体CSS吗?font.addFont ...
html 生成 pdf 实现思路和代码,基于itext -
feiyan35488:
好久不用ftl了,发现jsp其实还是蛮强大的
freemarker 源码分析 -
elliotann:
呵呵,我也是
freemarker 源码分析 -
lai555:
单步调试呢?
抛开myeclipse ,使用maven jetty 插件运行调试 web项目
首先 请求进入 FilterChainProxy 这个类
FilterChainProxy.java
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { FilterInvocation fi = new FilterInvocation(request, response, chain); List<Filter> filters = getFilters(fi.getRequestUrl()); if (filters == null || filters.size() == 0) { if (logger.isDebugEnabled()) { logger.debug(fi.getRequestUrl() + filters == null ? " has no matching filters" : " has an empty filter list"); } chain.doFilter(request, response); return; } VirtualFilterChain virtualFilterChain = new VirtualFilterChain(fi, filters); virtualFilterChain.doFilter(fi.getRequest(), fi.getResponse()); } public List<Filter> getFilters(String url) { if (stripQueryStringFromUrls) { // String query string - see SEC-953 int firstQuestionMarkIndex = url.indexOf("?"); if (firstQuestionMarkIndex != -1) { url = url.substring(0, firstQuestionMarkIndex); } } for (Map.Entry<Object, List<Filter>> entry : filterChainMap.entrySet()) { Object path = entry.getKey(); if (matcher.requiresLowerCaseUrl()) { url = url.toLowerCase(); if (logger.isDebugEnabled()) { logger.debug("Converted URL to lowercase, from: '" + url + "'; to: '" + url + "'"); } } boolean matched = matcher.pathMatchesUrl(path, url); if (logger.isDebugEnabled()) { logger.debug("Candidate is: '" + url + "'; pattern is " + path + "; matched=" + matched); } if (matched) { return entry.getValue(); } } return null; }
可以看出, FilterInvocation 是见 request 和 response ,chain 只是进行了封装, 然后根据 url 来判断这个请求是否需要进行拦截, 这里 getFilter() 方法是查询的 intercepter-url 中配置的 内容。(这里具体的内容在下面)
接下来就是执行所有的List<Filter> 。执行完所有的List<Filter>之后会继续执行容器的filterChain
VirtualFilterChain.java 这是 FilterChainProxy 的内部类
public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException { if (currentPosition == additionalFilters.size()) { if (logger.isDebugEnabled()) { logger.debug(fi.getRequestUrl() + " reached end of additional filter chain; proceeding with original chain"); } fi.getChain().doFilter(request, response); } else { currentPosition++; Filter nextFilter = additionalFilters.get(currentPosition - 1); if (logger.isDebugEnabled()) { logger.debug(fi.getRequestUrl() + " at position " + currentPosition + " of " + additionalFilters.size() + " in additional filter chain; firing Filter: '" + nextFilter + "'"); } nextFilter.doFilter(request, response, this); } }
下面先按顺序分析各Filter的作用 (security默认添加的filterChain,共11个 还有大概4,5个没有涉及到,以后涉及到再进行添加)
1.org.springframework.security.web.context.SecurityContextPersistenceFilter
(2.0中是这个HttpSessionContextIntegrationFilter)
从这个类所在的包路径 context,大致知道这个类 只处理 上下文
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) req; HttpServletResponse response = (HttpServletResponse) res; if (request.getAttribute(FILTER_APPLIED) != null) { // ensure that filter is only applied once per request chain.doFilter(request, response); return; } final boolean debug = logger.isDebugEnabled(); request.setAttribute(FILTER_APPLIED, Boolean.TRUE); if (forceEagerSessionCreation) { HttpSession session = request.getSession(); if (debug && session.isNew()) { logger.debug("Eagerly created session: " + session.getId()); } } HttpRequestResponseHolder holder = new HttpRequestResponseHolder(request, response); SecurityContext contextBeforeChainExecution = repo.loadContext(holder); try { SecurityContextHolder.setContext(contextBeforeChainExecution); chain.doFilter(holder.getRequest(), holder.getResponse()); } finally { SecurityContext contextAfterChainExecution = SecurityContextHolder.getContext(); // Crucial removal of SecurityContextHolder contents - do this before anything else. SecurityContextHolder.clearContext(); repo.saveContext(contextAfterChainExecution, holder.getRequest(), holder.getResponse()); request.removeAttribute(FILTER_APPLIED); if (debug) { logger.debug("SecurityContextHolder now cleared, as request processing completed"); } } }
从代码看: 在一次request中只执行一次,并生成 SecurityContext(从session中读取,如果session中没有就创建一个新的),注册到 SecurityContextHolder中,当请求执行完后,清除该SecurityContext 和request中的 filter_applied 属性。在源码中类注释提到: 这个类 一次请求中只能执行一次,并且它应该在 任何认证过程之前 执行。
============================华丽丽的分割线===========================
2,org.springframework.security.web.authentication.logout.LogoutFilter
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) req; HttpServletResponse response = (HttpServletResponse) res; if (requiresLogout(request, response)) { Authentication auth = SecurityContextHolder.getContext().getAuthentication(); if (logger.isDebugEnabled()) { logger.debug("Logging out user '" + auth + "' and transferring to logout destination"); } for (LogoutHandler handler : handlers) { handler.logout(request, response, auth); } logoutSuccessHandler.onLogoutSuccess(request, response, auth); return; } chain.doFilter(request, response); } /** * Allow subclasses to modify when a logout should take place. * * @param request the request * @param response the response * * @return <code>true</code> if logout should occur, <code>false</code> otherwise */ protected boolean requiresLogout(HttpServletRequest request, HttpServletResponse response) { String uri = request.getRequestURI(); int pathParamIndex = uri.indexOf(';'); if (pathParamIndex > 0) { // strip everything from the first semi-colon uri = uri.substring(0, pathParamIndex); } int queryParamIndex = uri.indexOf('?'); if (queryParamIndex > 0) { // strip everything from the first question mark uri = uri.substring(0, queryParamIndex); } if ("".equals(request.getContextPath())) { return uri.endsWith(filterProcessesUrl); } return uri.endsWith(request.getContextPath() + filterProcessesUrl); }
这个处理比较简单, 只是检查是否为 登出地址,是的话就退出然后返回,不是的话就进行下一个filter。
这个判断是否为登录地址我感觉很不正常,他判断是否以 logout_url 结尾,直接判断是否相等才对啊。
而且他根据 contextpath 是否为“” ,其实不用的,直接判断 contextPath+logout_url 即可。
org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter .java
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) req; HttpServletResponse response = (HttpServletResponse) res; if (!requiresAuthentication(request, response)) { chain.doFilter(request, response); return; } if (logger.isDebugEnabled()) { logger.debug("Request is to process authentication"); } Authentication authResult; try { authResult = attemptAuthentication(request, response); if (authResult == null) { // return immediately as subclass has indicated that it hasn't completed authentication return; } sessionStrategy.onAuthentication(authResult, request, response); } catch (AuthenticationException failed) { // Authentication failed unsuccessfulAuthentication(request, response, failed); return; } // Authentication success if (continueChainBeforeSuccessfulAuthentication) { chain.doFilter(request, response); } successfulAuthentication(request, response, authResult); } public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException { if (postOnly && !request.getMethod().equals("POST")) { throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod()); } String username = obtainUsername(request); String password = obtainPassword(request); if (username == null) { username = ""; } if (password == null) { password = ""; } username = username.trim(); UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password); // Place the last username attempted into HttpSession for views HttpSession session = request.getSession(false); if (session != null || getAllowSessionCreation()) { request.getSession().setAttribute(SPRING_SECURITY_LAST_USERNAME_KEY, TextEscapeUtils.escapeEntities(username)); } // Allow subclasses to set the "details" property setDetails(request, authRequest); return this.getAuthenticationManager().authenticate(authRequest); }
public Authentication doAuthentication(Authentication authentication) throws AuthenticationException { Class<? extends Authentication> toTest = authentication.getClass(); AuthenticationException lastException = null; Authentication result = null; for (AuthenticationProvider provider : getProviders()) { if (!provider.supports(toTest)) { continue; } logger.debug("Authentication attempt using " + provider.getClass().getName()); try { result = provider.authenticate(authentication); if (result != null) { copyDetails(authentication, result); break; } } catch (AccountStatusException e) { // SEC-546: Avoid polling additional providers if auth failure is due to invalid account status eventPublisher.publishAuthenticationFailure(e, authentication); throw e; } catch (AuthenticationException e) { lastException = e; } } if (result == null && parent != null) { // Allow the parent to try. try { result = parent.authenticate(authentication); } catch (ProviderNotFoundException e) { // ignore as we will throw below if no other exception occurred prior to calling parent and the parent // may throw ProviderNotFound even though a provider in the child already handled the request } catch (AuthenticationException e) { lastException = e; } } if (result != null) { if (eraseCredentialsAfterAuthentication && (result instanceof CredentialsContainer)) { // Authentication is complete. Remove credentials and other secret data from authentication ((CredentialsContainer)result).eraseCredentials(); } eventPublisher.publishAuthenticationSuccess(result); return result; } // Parent was null, or didn't authenticate (or throw an exception). if (lastException == null) { lastException = new ProviderNotFoundException(messages.getMessage("ProviderManager.providerNotFound", new Object[] {toTest.getName()}, "No AuthenticationProvider found for {0}")); } eventPublisher.publishAuthenticationFailure(lastException, authentication); throw lastException; }
过程: 判断是否 为登录地址,是则进行认证,否则 继续下一个filter
认证过程: 取得 username,password, 调用 AuthenticationManager.authenticate(){
然后调用 所有的AuthenticationProvider 进行认证,有一个认证通过即可通过。在AuthenticationProvider中调用 配置的 UserDetailsService 的 loadUserByUserame() 得到 UserDetails, 当第一次从数据库取得后,会将UserDetails保存到 Cache中,这给权限分配的 及时性带来了困难,不过它专门提供了一个filter来进行 热部署权限
}
还有一点,这个filter中判断 "j_spring_security_check"这个地址也是以 endWith来匹配的,感觉不对。
回家了,晚上继续
===========================华丽丽的分割线=================================
org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter
org.springframework.security.web.authentication.www.BasicAuthenticationFilter
org.springframework.security.web.savedrequest.RequestCacheAwareFilter
org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter
org.springframework.security.web.authentication.AnonymousAuthenticationFilter
org.springframework.security.web.session.SessionManagementFilter
org.springframework.security.web.access.ExceptionTranslationFilter
org.springframework.security.web.access.intercept.FilterSecurityInterceptor
发表评论
-
spring security 3.0 logout filter 代码中的一个小bug
2011-01-27 15:59 1026先附上 public void doF ... -
spring security 源码解读 1
2011-01-25 18:06 2122这一阵子看到了security,很感兴趣。于是研究一下,我在j ... -
spring 事件处理机制的原理分析和新的设想
2011-01-20 17:32 1010spring的事件处理 是这样做的: 所有需要监听或发布事件 ... -
spring 自定义事件 处理机制 2
2011-01-20 17:24 1035在SERVICE的抽象类中去掉onApplicationEve ... -
spring 自定义事件处理机制
2011-01-20 17:20 2898自定义的事件监听与处理框架。 如果只想监听到自已所关心的 ... -
spring的事件 处理机制
2011-01-20 17:17 1079基于SPRING的事件处理其实很简单,初学者不必一开始就担心搞 ... -
spring 事务 不能rollback的问题终于解决了
2011-01-13 18:10 2637项目中虽然配置了事务,但是总感觉没起作用。 尤其是我在测试s ... -
spring 详细配置
2011-01-13 16:38 904PROPAGATION_REQUIRED -- 支持当前事务, ... -
spring security遇到的一些问题
2011-01-12 17:08 1020昨天整理了 maven + jetty ... -
spring junit集成测试
2011-01-04 11:24 2062利用spring来进行集成测试 ... -
我要精通spring
2010-12-14 12:24 882刚学spring的时候就是按视频上的教的那样做着 ,遇到不会的 ... -
spring事物和db连接池的一些想法
2010-11-19 15:18 1339当用spring的事物来管理 hibernate的sessio ... -
今天用spring 事务出了一个很郁闷的问题
2010-11-11 17:40 1041这个项目采用 ssh 框架,使用spring的声明式代理拦截器 ...
相关推荐
### Spring Security 源码分析知识点 #### 一、Spring Security 概述 Spring Security 是一个强大且可高度定制的身份验证和访问控制框架。它提供了许多功能,包括登录表单、记住密码、CSRF 保护等。为了更好地理解...
在学习SpringSecurity源码时,建议从以下几个方面入手: 1. **源码结构分析**:了解主要组件的类结构和它们之间的关系,如`Authentication`、`Authorization`、`FilterChainProxy`等。 2. **关键类的实现**:深入...
通过阅读《Spring Security3.pdf》和《spring security3 源码分析.pdf》这两份文档,你可以对Spring Security 3的内部工作机制有更深入的理解,从而更好地在项目中运用这个强大的安全框架。同时,这也会帮助你在面临...
Spring Security的核心在于Filter Chain,它由多个安全相关的过滤器组成,如DelegatingFilterProxy、ChannelProcessingFilter、SecurityContextHolderAwareRequestFilter等。每个过滤器都有特定职责,如检查HTTP请求...
在深入分析SpringSecurity源码之前,我们先了解一些基础概念。 1. DelegatingFilterProxy:这是一个Spring框架提供的过滤器,它作为代理来调用实际的Filter。在web.xml中,filter-name设置为...
Spring Security 由多个组件构成,包括过滤器链、访问决策管理器、安全上下文持有者等。核心组件是`DelegatingFilterProxy`,它是一个Servlet过滤器,用于代理其他Spring Bean(如`...
1. **Filter Security Interceptor**:这是SpringSecurity的主要过滤器,负责检查请求并决定是否允许访问。它会根据预定义的访问控制规则进行判断。 2. **Authentication Manager**:处理用户认证的组件,可以使用...
本篇文章将深入探讨Spring Security的核心概念和源码分析。 1. **核心组件** - `SecurityContextHolder`: 它是Spring Security的核心,存储当前请求的安全上下文,包含认证信息和权限。 - `Authentication`: 表示...
3. **Filter Chain(过滤器链)**:Spring Security的核心在于其Web安全过滤器链,如`DelegatingFilterProxy`、`FilterSecurityInterceptor`和`ChannelProcessingFilter`等。这些过滤器在HTTP请求进入应用之前进行...
在源码分析中,你可能会看到SpringSecurity如何利用过滤器链来处理HTTP请求,如`UsernamePasswordAuthenticationFilter`用于处理登录请求,`AnonymousAuthenticationFilter`确保未认证用户默认有一个匿名角色,还有`...
在分析Spring Security源码时,你可能会关注以下关键组件: - `AbstractSecurityInterceptor`:所有安全拦截器的基类。 - `FilterSecurityInterceptor`:处理HTTP请求的安全过滤器。 - `AuthenticationManager` 和 `...
Spring Security OAuth2 是一个强大的框架,用于为Java应用提供OAuth2和OpenID Connect...通过阅读和分析`spring-security-oauth-master`中的源码,可以更深入地了解其实现细节,有助于在实际项目中灵活运用和定制。
- 通过源码分析,了解Spring Security的拦截器如何工作,以及如何自定义安全规则。 - 查看`SecurityConfig`类,这是Spring Security的核心配置,它扩展了`WebSecurityConfigurerAdapter`并覆盖了一些关键方法。 -...
Spring Security基于过滤器链的概念,其核心组件包括AuthenticationManager、UserDetailsService、AccessDecisionManager等。AuthenticationManager负责处理用户认证,UserDetailsService则用于查找用户信息,...
`springsecurity-sample.rar` 可能包含一个示例项目,展示如何集成 Spring Security 并进行基本配置。这个样本项目可能包括以下部分: 1. **SecurityConfig**: 定义安全规则的 Java 类,可能使用 `@...
- **过滤器链(Filter Chain)**:Spring Security的核心在于一系列的过滤器,它们按特定顺序拦截请求,处理认证和授权。 2. **主要组件**: - **AuthenticationProvider**:处理用户的认证请求,实现具体的认证...
`src`目录下的代码应包含关键组件,如`WebSecurityConfig`配置类、`UserDetailsService`实现、以及可能的自定义过滤器或访问决策器。通过阅读和理解这些代码,可以更深入地了解Spring Security的运作机制。 总之,...
Spring Security 是一个强大的和高度可定制的身份验证和访问控制框架,用于Java应用...通过分析源码,我们可以学习如何实现自定义的身份验证提供者、授权策略,甚至构建自己的安全过滤器,以提高应用的安全性和可靠性。
3. **Filter Security Interceptor**:这是一个关键的过滤器,负责检查请求的URL是否需要授权。如果需要,它会触发认证过程。你将在案例中看到如何配置这些拦截器以定义安全规则。 4. **Access Decision Manager**...
1. **Filter Chain**: Spring Security的核心在于其过滤器链,它由多个安全过滤器组成,如`DelegatingFilterProxy`、`ChannelProcessingFilter`、`UsernamePasswordAuthenticationFilter`等。这些过滤器按照特定顺序...