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

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
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值