acegi security實踐教程—basic認證之debug調試

來源:互聯網
上載者:User

debug調試: 運行:http://localhost:8080/acegitest1/index.jsp 因為web.xml中配置:

      <filter-name >AcegiFilterChainProxy </filter-name >         <filter-class >            org.acegisecurity.util.FilterToBeanProxy         </filter-class >       <init-param >      <param-name >targetBean </param-name >      <param-value >filterChainProxy </param-value >      </init-param >
  1. 進入:FilterToBeanProxy代理類中的doFilter,因為init只執行一次,啟動時已經執行一次,所以訪問url時,直接直接進入doFilter方法。  
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)        throws IOException, ServletException {        if (!initialized ) {            doInit();        }        delegate.doFilter(request, response, chain);    }
2. 進入:目標類filterChainProxy 中的doFilter
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)        throws IOException, ServletException {        FilterInvocation fi = new FilterInvocation(request, response, chain);        ConfigAttributeDefinition cad = this.filterInvocationDefinitionSource .getAttributes(fi);        if (cad == null) {            if ( logger.isDebugEnabled()) {                logger.debug(fi.getRequestUrl() + " has no matching filters");            }            chain.doFilter(request, response);            return;        }        Filter[] filters = obtainAllDefinedFilters(cad);        if (filters.length == 0) {            if ( logger.isDebugEnabled()) {                logger.debug(fi.getRequestUrl() + " has an empty filter list");            }            chain.doFilter(request, response);            return;        }        VirtualFilterChain virtualFilterChain = new VirtualFilterChain(fi, filters);        virtualFilterChain.doFilter(fi.getRequest(), fi.getResponse());    }
   這個方法,主要擷取aceg設定檔中,使用者配置了多少個filter,並且filter順序以數組形式展示,這樣就開始filter過濾連了。3.進入:過濾連第一個filter,也就是咱們配置的basicProcessingFilter,其中doFilter如下: 
      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;        String header = httpRequest.getHeader( "Authorization");        if (logger.isDebugEnabled()) {            logger.debug( "Authorization header: " + header);        }        if ((header != null) && header.startsWith( "Basic ")) {            String base64Token = header.substring(6);            String token = new String(Base64.decodeBase64(base64Token.getBytes()));            String username = "";            String password = "";            int delim = token.indexOf( ":");            if (delim != -1) {                username = token.substring(0, delim);                password = token.substring(delim + 1);            }            if (authenticationIsRequired(username)) {                UsernamePasswordAuthenticationToken authRequest =                        new UsernamePasswordAuthenticationToken(username, password);                authRequest.setDetails(authenticationDetailsSource .buildDetails((HttpServletRequest) request));                Authentication authResult;                try {                    authResult = authenticationManager.authenticate(authRequest);                } catch (AuthenticationException failed) {                    // Authentication failed                    if ( logger.isDebugEnabled()) {                        logger.debug( "Authentication request for user: " + username + " failed: " + failed.toString());                    }                    SecurityContextHolder.getContext().setAuthentication( null);                    if ( rememberMeServices != null) {                        rememberMeServices.loginFail(httpRequest, httpResponse);                    }                    if ( ignoreFailure) {                        chain.doFilter(request, response);                    } else {                        authenticationEntryPoint.commence(request, response, failed);                    }                    return;                }                // Authentication success                if ( logger.isDebugEnabled()) {                    logger.debug( "Authentication success: " + authResult.toString());                }                SecurityContextHolder.getContext().setAuthentication(authResult);                if ( rememberMeServices != null) {                    rememberMeServices.loginSuccess(httpRequest, httpResponse, authResult);                }            }        }        chain.doFilter(request, response);    }
   這個關鍵在於 if ((header !=  null) && header.startsWith( "Basic ")),其中basic認證是把使用者輸入使用者名稱和密碼存放到header中,basic認證的。因為這個header為null【稍後在分析header】,所以執行下一個filter。4.進入exceptionfilter5.進入filterInvocationInterceptor
     public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)        throws IOException, ServletException {        FilterInvocation fi = new FilterInvocation(request, response, chain);        invoke(fi);    }
    跟著進去invoke,然後進入InterceptorStatusToken token =  super.beforeInvocation(fi);最後關鍵處在於ConfigAttributeDefinition attr =  this.obtainObjectDefinitionSource ().getAttributes(object);   obtainObjectDefinitionSource 大家眼熟吧,就是acegi設定檔,配置那個檔案有那個角色。因為index.jsp沒有配置,所以擷取為null6.類似回呼函數,一步步返回。這個頁面就執行了一遍,即使exceptionfilter捕捉了異常,但是因為index.jsp沒有配置授權的事情,所以異常filter中的異常策略authenticationEntryPoint沒執行。  index.jsp訪問完畢,我們來調試訪問受保護的頁面security.jsp,因為acegi進行配置了。上述已經把基本的流程跟大家調通,接下來就是不同之處,當然也是這個過濾連流程。因為訪問受保護的資源,所以捕捉沒有輸入使用者名稱和密碼,然後異常交給basic處理,basic認證是彈出框,輸入使用者名稱和密碼的。  那我們輸入正確有效使用者,測試如下:  header如下:   你配置保護urlObjectDefinitionSource擷取許可權:
    public ConfigAttributeDefinition lookupAttributes(String url) {        // Strip anything after a question mark symbol, as per SEC-161. See also SEC-321        int firstQuestionMarkIndex = url.indexOf( "?");        if (firstQuestionMarkIndex != -1) {            url = url.substring(0, firstQuestionMarkIndex);        }        if (isConvertUrlToLowercaseBeforeComparison()) {            url = url.toLowerCase();            if ( logger.isDebugEnabled()) {                logger.debug( "Converted URL to lowercase, from: '" + url + "'; to: '" + url + "'");            }        }        Iterator iter = requestMap.iterator();        while (iter.hasNext()) {            EntryHolder entryHolder = (EntryHolder) iter.next();            boolean matched = pathMatcher.match(entryHolder.getAntPath(), url);            if ( logger.isDebugEnabled()) {                logger.debug( "Candidate is: '" + url + "'; pattern is " + entryHolder.getAntPath() + "; matched="                    + matched);            }            if (matched) {                return entryHolder.getConfigAttributeDefinition();            }        }        return null;    }
   進行投票機制:  關鍵代碼:
     authenticated = SecurityContextHolder.getContext().getAuthentication();     this. accessDecisionManager .decide(authenticated, object, attr);     public int vote(Authentication authentication, Object object, ConfigAttributeDefinition config) {        int result = ACCESS_ABSTAIN;        Iterator iter = config.getConfigAttributes();        while (iter.hasNext()) {            ConfigAttribute attribute = (ConfigAttribute) iter.next();            if ( this.supports(attribute)) {                result = ACCESS_DENIED;                // Attempt to find a matching granted authority                for ( int i = 0; i < authentication.getAuthorities().length ; i++) {                    if (attribute.getAttribute().equals(authentication.getAuthorities()[i].getAuthority())) {                        return ACCESS_GRANTED;                    }                }            }        }        return result;    }       while (iter.hasNext()) {            AccessDecisionVoter voter = (AccessDecisionVoter) iter.next();            int result = voter.vote(authentication, object, config);            switch (result) {            case AccessDecisionVoter. ACCESS_GRANTED:                return;            case AccessDecisionVoter. ACCESS_DENIED:                deny++;                break;            default:                break;            }        }        if (deny > 0) {            throw new AccessDeniedException(messages.getMessage("AbstractAccessDecisionManager.accessDenied" ,                    "Access is denied"));        }
      上述給的不是特別完整的代碼,但是都是很關鍵的代碼。大家可以下載源碼,然後自己debug調試,同時我也會把acegi源碼附上。      一般情況下完整的系統很少使用basic認證,因為每個系統都有自己的登陸頁,若未登陸應該跳轉到登陸頁面,若許可權不足,應該跳轉到accessdefined頁面。那我們下篇部落格搭建基於表單認證。       項目源碼:

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.