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

来源:互联网 发布:tscttp244pro标签软件 编辑:程序博客网 时间:2024/06/05 03:16
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.进入exceptionfilter
5.进入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没有配置,所以获取为null
6.类似回调函数,一步步返回。这个页面就执行了一遍,即使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页面。那我们下篇博客搭建基于表单认证。
       项目源码:

2 0
原创粉丝点击