美文网首页spring security
Spring Security原理篇(七) 认证流程

Spring Security原理篇(七) 认证流程

作者: 怪诞140819 | 来源:发表于2018-09-19 17:02 被阅读229次

    上文已经说了Spring Security启动bean是怎样被加载到spring容器。也说到了默认情况下的过滤器链里面的11个过滤器。
    UsernamePasswordAuthenticationFilter负责的就是对用户名密码进行认证。

    1.UsernamePasswordAuthenticationFilter的实现原理

    • 拦截请求
    public UsernamePasswordAuthenticationFilter() {
        super(new AntPathRequestMatcher("/login", "POST"));
    }
    

    /login的请求进行拦截,我们看到请求类型只能是POST

    • 允许对用户名密码的参数进行定义,默认情况下是usernamepassword
    • 认证的过程
      我们看一下doFilter()方法,这个方法定义在父类AbstractAuthenticationProcessingFilter
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
                throws IOException, ServletException {
    
            HttpServletRequest request = (HttpServletRequest) req;
            HttpServletResponse response = (HttpServletResponse) res;
    
            if (!requiresAuthentication(request, response)) {
                chain.doFilter(request, response);
    
                return;
            }
    
            if (logger.isDebugEnabled()) {
                logger.debug("Request is to process authentication");
            }
    
            Authentication authResult;
    
            try {
                authResult = attemptAuthentication(request, response);
                if (authResult == null) {
                    // return immediately as subclass has indicated that it hasn't completed
                    // authentication
                    return;
                }
                sessionStrategy.onAuthentication(authResult, request, response);
            }
            catch (InternalAuthenticationServiceException failed) {
                logger.error(
                        "An internal error occurred while trying to authenticate the user.",
                        failed);
                unsuccessfulAuthentication(request, response, failed);
    
                return;
            }
            catch (AuthenticationException failed) {
                // Authentication failed
                unsuccessfulAuthentication(request, response, failed);
    
                return;
            }
    
            // Authentication success
            if (continueChainBeforeSuccessfulAuthentication) {
                chain.doFilter(request, response);
            }
    
            successfulAuthentication(request, response, chain, authResult);
        }
    

    这个方法调用了attemptAuthentication()方法,这个方法定义在子类UsernamePasswordAuthenticationFilter
    成功调用sessionStrategy.onAuthentication()方法处理session,然后在调用successfulAuthentication()这个方法处理操作成功
    失败调用unsuccessfulAuthentication()方法,处理失败信息

    我们看一下attemptAuthentication()这个方法

    public Authentication attemptAuthentication(HttpServletRequest request,
                HttpServletResponse response) throws AuthenticationException {
            if (postOnly && !request.getMethod().equals("POST")) {
                throw new AuthenticationServiceException(
                        "Authentication method not supported: " + request.getMethod());
            }
    
            String username = obtainUsername(request);
            String password = obtainPassword(request);
    
            if (username == null) {
                username = "";
            }
    
            if (password == null) {
                password = "";
            }
    
            username = username.trim();
    
            UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(
                    username, password);
    
            // Allow subclasses to set the "details" property
            setDetails(request, authRequest);
    
            return this.getAuthenticationManager().authenticate(authRequest);
        }
    

    其实我们从这段代码可以看到这个方法机会只做了几件事情
    1.验证是不是POST类型的请求
    2.获取参数
    3.调用AuthenticationManager的authenticate()方法进行认证
    4.认证成功返回一个Authentication类型变量,认证失败抛出AuthenticationException异常
    5.综上所述,认证的处理其实是委托给了AuthenticationManager来做处理的

    2.AuthenticationManager怎样处理认证

    • 先看一下处理的流程图


      认证流程

    由于源代码比较简单所以不引入源代码,然而有几个类我们都没有见过,需要好好的看一下

    2.1 AuthenticationManager 接口

    这个接口值定义了一个方法

    Authentication authenticate(Authentication authentication)throws AuthenticationException;
    

    从注释中我们可以知道,一旦验证成功会填充好Authentication对象,包括权限的信息,同时这个方法的实现必须遵循以下约定

    • 1.如果账号不可用,抛出异常DisabledException
    • 2.如果账号锁定,抛出异常LockedException
    • 3.如果密码错误,抛出异常 BadCredentialsException
    • 4.不可用和已锁定的账号应该立即抛出异常,不能再进行密码验证

    2.2 ProviderManager

    • ProviderManagerAuthenticationManager的实现类
    • 看一下其中的一个变量
    private List<AuthenticationProvider> providers = Collections.emptyList();
    

    里面存储了需要验证的provider,然后循环利用provider进行验证,稍后我们看一下具体的一个provider的实现

    • 所以ProviderManager负责的是组合各种provider进行验证

    2.3 AuthenticationProvider接口

    public interface AuthenticationProvider {
        Authentication authenticate(Authentication authentication)throws AuthenticationException;
        boolean supports(Class<?> authentication);
    }
    
    • 这个接口里面主要定义了两个方法
    • 常用的实现类DaoAuthenticationProvider由于逻辑比较简单可以自行查看源代码,
      主要是用UserDetailsService根据username获取到用户,然后再比较密码是否相同来完成验证的逻辑
    • AuthenticationProvider表示某一个具体的验证规则

    2.4 Authentication

    这个是DaoAuthenticationProvider验证成功后创建Authentication

    image.png

    我们可以看到的是 Authentication里面存放的是主体(简单点就是用户吧)认证或者认证成功后的信息

    相关文章

      网友评论

        本文标题:Spring Security原理篇(七) 认证流程

        本文链接:https://www.haomeiwen.com/subject/qgibnftx.html