- 浏览: 249953 次
- 性别:
- 来自: 苏州
文章分类
- 全部博客 (289)
- java (72)
- oracle (3)
- mysql (5)
- spring (28)
- hibernate (2)
- osgi (0)
- linux (2)
- ExtJs (1)
- jvm (0)
- mybatis (7)
- 分布式 (11)
- MINA (6)
- apache+tomcat (13)
- js+htm (7)
- android (44)
- http (1)
- hbase+hdoop (0)
- memcache (13)
- search (27)
- 部署及性能 (12)
- mongoDB (2)
- 多线程 (12)
- 安全管理验证 (9)
- struts (1)
- webservice (0)
- easyUI (1)
- spring security (16)
- pattern (6)
- 算法 (2)
最新评论
-
lzh8189146:
CommonsHttpSolrServer这个类,现在是不是没 ...
CommonsHttpSolrServer -
xiaochanzi:
我按照你的方法试了下,tomcat6可以发布,但是访问任何网页 ...
基于内嵌Tomcat的应用开发 -
phoneeye:
麻烦你,如果是抄来的文章,请给出来源。谢谢
ant 两则技巧 -
neverforget:
转载不注明出处
Spring Security3.1登陆验证 替换 usernamepasswordfilter -
liang1022:
若不使用eclipse ,如何在命令行下 运行服务端程序 ?
WebService CXF学习(入门篇2):HelloWorld
首先 请求进入 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());
- }
- ublic 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 {
- <span style="color: #ff0000;"> if (currentPosition == additionalFilters.size()) {
- </span> if (logger.isDebugEnabled()) {
- logger.debug(fi.getRequestUrl()
- + " reached end of additional filter chain; proceeding with original chain");
- }
- <span style="color: #ff0000;">
- fi.getChain().doFilter(request, response);</span>
- } 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 即可。
- 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 security3上实现验证码
2012-04-21 16:07 613在spring security3上实现验证码 h ... -
Spring Security3.1登陆验证 替换 usernamepasswordfilter
2012-04-15 02:01 3370一、前言 在上一篇http://blog.c ... -
Spring Security 3应用的11个步骤
2012-04-15 01:47 1128Spring Security 3应用的11个步骤 ... -
在spring security3上实现验证码
2012-03-01 08:44 600转载: 在spring securi ... -
spring security 密码编码器
2012-03-14 08:13 931spring security 密码编码器 (2 ... -
spring security 配置详解
2012-02-25 11:50 2137http://static.springsource.org/ ... -
图解Spring Security默认使用的过滤器
2012-02-24 08:13 738转载:http://www.flyysoft.com/plus ... -
Spring Security 3 与 CAS单点登录配置-Server
2012-03-15 19:56 1257转载:http://www.hxdw.com/bbs/post ... -
Topic: Spring Security 3 与 CAS单点登录配置-Client
2012-02-26 12:12 791转载: http://www.hxdw.com ... -
Spring Security 可动态授权RBAC权限模块实践
2012-02-19 13:25 2010Spring Security 可动态授权RBA ... -
Spring Security 3 基于角色访问控制过程详解
2012-02-19 13:25 1373访问控制:由于我们配 ... -
修改spring security源码实现动态授权
2012-02-21 08:15 885修改spring security源码实现动态 ... -
spring security 3.0 logout filter 代码中的一个小bug
2012-03-15 19:57 962spring security 3.0 log ... -
spring security遇到的一些问题
2012-03-19 08:24 635spring security遇到的一些问题 ... -
spring security 源码解读 1
2012-03-19 08:24 835http://feiyan35488.iteye.com/bl ...
相关推荐
在集成 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...