美文网首页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