acegi security实践教程—form认证之debug调试

  运行基于form表单的acegitest2demo,你是否发现有什么不妥?
  测试不妥处如下:
  2.肯定会转到login页面,然后登陆进去test/1,进入accessdefined无权限页面。使用lisi/1,进入当前用户信息。

  但是:
  假如你用test/1登陆进去的,当再次运行http://localhost:8080/acegitest2/userinfo.jsp,你猜猜会出现什么现象呢?
  哈哈,进入accessdefined无权限页面。
  我再打开IE浏览器,再运行这个url,还是进入无权限页面。
  是缓存?那我明明是新打开的浏览器啊,而不是打开新标签啊?
  无论你打开几层IE浏览器,你F12看看,会发现,咦,sessionId是相同的。

  这说明什么问题?说明你用的IE浏览器是session共享的,这是浏览器为用户方便而专门为用户设置的。IE8默认情况下,session是共享的。

  那如何新建一个session不同的页面呢?
  在IE中,文件—新建session会话即可。
  修改浏览器的快捷方式属性,在 C:\Program Files\Internet Explorer 文件夹下,通过iexplore.exe 新建一快捷方式至桌面,在桌面的快捷方式上点击右键选择属性,修改“目标”为 "C:\Program Files\Internet Explorer\iexplore.exe" -nomerge  通过此快捷方式启动的浏览器不会共享会话
  
  按照以上方式,更改了,再运行url,还是进入无权限页面,发现跟session没关系【后面会讲跟session有关系的博文】,你使用360、谷歌测试,都是相同页面。
  
  进入debug调试……【当初debug时,漏掉一个方法,导致误以为是session的问题】
  因为咱们配置acegi的filter是:authenticationProcessingFilter,exceptionTranslationFilter,
,filterInvocationInterceptor这三个,其中第一个是身份认证的,debug首先进入第一个filter,但是实际上是进入AbstractProcessingFilter,而authenticationProcessingFilter是extends AbstractProcessingFilter,其中第一个filter的方法:
  
     public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException,
                ServletException {
            if (!(request instanceof HttpServletRequest)) {
                 throw new ServletException( "Can only process HttpServletRequest");
           }

            if (!(response instanceof HttpServletResponse)) {
                 throw new ServletException( "Can only process HttpServletResponse");
           }

           HttpServletRequest httpRequest = (HttpServletRequest) request;
           HttpServletResponse httpResponse = (HttpServletResponse) response;

            if (requiresAuthentication(httpRequest, httpResponse)) {
                 if ( logger.isDebugEnabled()) {
                      logger.debug( "Request is to process authentication");
                }

                Authentication authResult;

                 try {
                     onPreAuthentication(httpRequest, httpResponse);
                     authResult = attemptAuthentication(httpRequest);
                }
                 catch (AuthenticationException failed) {
                      // Authentication failed
                     unsuccessfulAuthentication(httpRequest, httpResponse, failed);

                      return;
                }

                 // Authentication success
                 if ( continueChainBeforeSuccessfulAuthentication) {
                     chain.doFilter(request, response);
                }

                successfulAuthentication(httpRequest, httpResponse, authResult);

                 return;
           }

           chain.doFilter(request, response);
     }

  其中的分支点在于:requiresAuthentication(httpRequest, httpResponse)这个方法;根据名称猜测到是否需要验证的意思。当第一次运行时,这个为true,然后进入其中身份认证。但是第二次执行时,就false,直接跳到下一个filter。
  exceptionfilter这个就是捕捉错误的,不多谈了。
  然后再进入授权filter-filterInvocationInterceptor,获取SecurityContextHolder.getContext().getAuthentication(),其中securitycontex中存在权限对象,然后直接进入decide投票方法。
  那么关键问题在于,为啥securitycontext中保留上次的权限对象?
  在第一个fiter认证后,securitycontext把已经通过认证对象保存进去successfulAuthentication,
 SecurityContextHolder.getContext().setAuthentication(authResult);
 这样在filterInvocationInterceptor中,关键代码如下:
     
 if (!SecurityContextHolder.getContext().getAuthentication().isAuthenticated() || alwaysReauthenticate) {
                 try {
                     authenticated = this. authenticationManager.authenticate(SecurityContextHolder. getContext()
                                .getAuthentication());
                }
                 catch (AuthenticationException authenticationException) {
                      throw authenticationException;
                }

                 // We don't authenticated.setAuthentication(true), because each
                 // provider should do that
                 if ( logger.isDebugEnabled()) {
                      logger.debug( "Successfully Authenticated: " + authenticated.toString());
                }

                SecurityContextHolder. getContext().setAuthentication(authenticated);
           }
            else {
                authenticated = SecurityContextHolder.getContext().getAuthentication();

                 if ( logger.isDebugEnabled()) {
                      logger.debug( "Previously Authenticated: " + authenticated.toString());
                }
           } 
      
    直接获取其中的权限对象,进行投票匹配。

    这篇博客主要分析了form认证的关键代码,那下篇博客我们看看若添加了sessionfilter,会有什么变化呢?
   
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章