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,會有什麼變化呢?
   
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章