- 浏览: 198045 次
- 性别:
- 来自: 北京
文章分类
最新评论
-
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 985先附上 public void doF ... -
spring security 源码解读 1
2011-01-25 18:06 2069这一阵子看到了security,很感兴趣。于是研究一下,我在j ... -
spring 事件处理机制的原理分析和新的设想
2011-01-20 17:32 981spring的事件处理 是这样做的: 所有需要监听或发布事件 ... -
spring 自定义事件 处理机制 2
2011-01-20 17:24 1012在SERVICE的抽象类中去掉onApplicationEve ... -
spring 自定义事件处理机制
2011-01-20 17:20 2874自定义的事件监听与处理框架。 如果只想监听到自已所关心的 ... -
spring的事件 处理机制
2011-01-20 17:17 1040基于SPRING的事件处理其实很简单,初学者不必一开始就担心搞 ... -
spring 事务 不能rollback的问题终于解决了
2011-01-13 18:10 2591项目中虽然配置了事务,但是总感觉没起作用。 尤其是我在测试s ... -
spring 详细配置
2011-01-13 16:38 877PROPAGATION_REQUIRED -- 支持当前事务, ... -
spring security遇到的一些问题
2011-01-12 17:08 990昨天整理了 maven + jetty ... -
spring junit集成测试
2011-01-04 11:24 2037利用spring来进行集成测试 ... -
我要精通spring
2010-12-14 12:24 847刚学spring的时候就是按视频上的教的那样做着 ,遇到不会的 ... -
spring事物和db连接池的一些想法
2010-11-19 15:18 1305当用spring的事物来管理 hibernate的sessio ... -
今天用spring 事务出了一个很郁闷的问题
2010-11-11 17:40 986这个项目采用 ssh 框架,使用spring的声明式代理拦截器 ...
相关推荐
在集成 Spring Security 安全框架的时候我们最先处理的可能就是根据我们项目的实际需要来定制注册登录了,尤其是 Http 登录认证。根据以前的相关文章介绍, Http 登录...今天我们就简单分析它的源码和工作流程。
Java 源码包 Applet钢琴模拟程序java源码 2个目标文件,提供基本的音乐编辑功能。编辑音乐软件的朋友,这款实例会对你有所帮助。 Calendar万年历 1个目标文件 EJB 模拟银行ATM流程及操作源代码 6个目标文件,EJB来...
笔者当初为了学习JAVA,收集了很多经典源码,源码难易程度分为初级、中级、高级等,详情看源码列表,需要的可以直接下载! 这些源码反映了那时那景笔者对未来的盲目,对代码的热情、执着,对IT的憧憬、向往!此时此...
Spring4GWT ...JARP是为petri 网提供的一个Java编辑器,基于ARP分析器。可以将网络图导出为 GIF, JPEG, PNG, PPM, ARP and PNML (XML based)文件格式。使用了优秀的JHotDraw 5.2 框架。 activemq...
Spring4GWT ...JARP是为petri 网提供的一个Java编辑器,基于ARP分析器。可以将网络图导出为 GIF, JPEG, PNG, PPM, ARP and PNML (XML based)文件格式。使用了优秀的JHotDraw 5.2 框架。 activemq...
Spring4GWT ...JARP是为petri 网提供的一个Java编辑器,基于ARP分析器。可以将网络图导出为 GIF, JPEG, PNG, PPM, ARP and PNML (XML based)文件格式。使用了优秀的JHotDraw 5.2 框架。 activemq...
Spring4GWT ...JARP是为petri 网提供的一个Java编辑器,基于ARP分析器。可以将网络图导出为 GIF, JPEG, PNG, PPM, ARP and PNML (XML based)文件格式。使用了优秀的JHotDraw 5.2 框架。 activemq...
Spring4GWT ...JARP是为petri 网提供的一个Java编辑器,基于ARP分析器。可以将网络图导出为 GIF, JPEG, PNG, PPM, ARP and PNML (XML based)文件格式。使用了优秀的JHotDraw 5.2 框架。 activemq...
Spring4GWT ...JARP是为petri 网提供的一个Java编辑器,基于ARP分析器。可以将网络图导出为 GIF, JPEG, PNG, PPM, ARP and PNML (XML based)文件格式。使用了优秀的JHotDraw 5.2 框架。 activemq...
Spring4GWT ...JARP是为petri 网提供的一个Java编辑器,基于ARP分析器。可以将网络图导出为 GIF, JPEG, PNG, PPM, ARP and PNML (XML based)文件格式。使用了优秀的JHotDraw 5.2 框架。 activemq...
Spring4GWT ...JARP是为petri 网提供的一个Java编辑器,基于ARP分析器。可以将网络图导出为 GIF, JPEG, PNG, PPM, ARP and PNML (XML based)文件格式。使用了优秀的JHotDraw 5.2 框架。 activemq...
Spring4GWT ...JARP是为petri 网提供的一个Java编辑器,基于ARP分析器。可以将网络图导出为 GIF, JPEG, PNG, PPM, ARP and PNML (XML based)文件格式。使用了优秀的JHotDraw 5.2 框架。 activemq...
Spring4GWT ...JARP是为petri 网提供的一个Java编辑器,基于ARP分析器。可以将网络图导出为 GIF, JPEG, PNG, PPM, ARP and PNML (XML based)文件格式。使用了优秀的JHotDraw 5.2 框架。 activemq...
Spring4GWT ...JARP是为petri 网提供的一个Java编辑器,基于ARP分析器。可以将网络图导出为 GIF, JPEG, PNG, PPM, ARP and PNML (XML based)文件格式。使用了优秀的JHotDraw 5.2 框架。 activemq...
Spring4GWT ...JARP是为petri 网提供的一个Java编辑器,基于ARP分析器。可以将网络图导出为 GIF, JPEG, PNG, PPM, ARP and PNML (XML based)文件格式。使用了优秀的JHotDraw 5.2 框架。 activemq...
Spring4GWT ...JARP是为petri 网提供的一个Java编辑器,基于ARP分析器。可以将网络图导出为 GIF, JPEG, PNG, PPM, ARP and PNML (XML based)文件格式。使用了优秀的JHotDraw 5.2 框架。 activemq...