通过【从授权开始看源码】我们可以看到这里主要就是干了几件事情

- 通过filter 确定登录要过滤的url
- 通过filter 确定生成的`AbstractAuthenticationToken` 比如 `UsernamePasswordAuthenticationToken`
- 通过生成的`AbstractAuthenticationToken` 确定`AuthenticationProvider`
- 通过`AuthenticationProvider` 最后调用 `authenticate()`方法最后进行授权



根据上面我们对自己对代码进行了一些封装

我们先来看`LoginAuthenticationFilter`

```java
public class LoginAuthenticationFilter extends UsernamePasswordAuthenticationFilter {

    private AuthenticationTokenParser authenticationTokenParser;

    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {

        AbstractAuthenticationToken authRequest  =  authenticationTokenParser.parse(requestBody);

        return this.getAuthenticationManager().authenticate(authRequest);
    }


    public void setAuthenticationTokenParser(AuthenticationTokenParser authenticationTokenParser) {
        this.authenticationTokenParser = authenticationTokenParser;
    }
}
```

这里的登录继承了`UsernamePasswordAuthenticationFilter`  里面写了

```java
public UsernamePasswordAuthenticationFilter() {
   super(new AntPathRequestMatcher("/login", "POST"));
}
```

这就是为什么登录的接口是`/login`的原因



我们再来看看生成`AbstractAuthenticationToken `的方法

`AbstractAuthenticationToken authRequest = authenticationTokenParser.parse(requestBody);`

这里决定了生成什么token，将会决定后面的`AuthenticationProvider`



我们先来看`AdminAuthenticationProvider`

```
    @Override
    public boolean supports(Class<?> authentication) {
        return AdminAuthenticationToken.class.isAssignableFrom(authentication);
    }
```

这里决定`AdminAuthenticationToken` 是通过`AdminAuthenticationProvider` 进行校验



再来看下完整的`AdminAuthenticationProvider` 你就知道验证码在哪里校验的了，是不是很简单

```java
public class AdminAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider {

    private final YamiUserDetailsService yamiUserDetailsService;

    private final PasswordEncoder passwordEncoder;

    @Override
    protected UserDetails retrieveUser(String username, Authentication authentication) throws BaseYamiAuth2Exception {
        UserDetails user;
        try {
            user = yamiUserDetailsService.loadUserByUsername(username);
        } catch (UsernameNotFoundExceptionBase var6) {
            throw new UsernameNotFoundExceptionBase("账号或密码不正确");
        }
        if (!user.isEnabled()) {
            throw new UsernameNotFoundExceptionBase("账号已被锁定,请联系管理员");
        }
        return user;
    }

    @Override
    protected void additionalAuthenticationChecks(UserDetails sysUser, Authentication authentication) throws BaseYamiAuth2Exception {
        AdminAuthenticationToken adminAuthenticationToken = (AdminAuthenticationToken) authentication;

        String kaptchaKey = SecurityConstants.SPRING_SECURITY_RESTFUL_IMAGE_CODE + adminAuthenticationToken.getSessionUUID();

        String kaptcha = RedisUtil.get(kaptchaKey);

        RedisUtil.del(kaptchaKey);

        if(StrUtil.isBlank(adminAuthenticationToken.getImageCode()) || !adminAuthenticationToken.getImageCode().equalsIgnoreCase(kaptcha)){
            throw new ImageCodeNotMatchExceptionBase("验证码有误");
        }



        String encodedPassword = sysUser.getPassword();
        String rawPassword = authentication.getCredentials().toString();

        // 密码不正确
        if (!passwordEncoder.matches(rawPassword,encodedPassword)){
            throw new BadCredentialsExceptionBase("账号或密码不正确");
        }
    }

    @Override
    protected Authentication createSuccessAuthentication(Authentication authentication, UserDetails user) {
        AdminAuthenticationToken result = new AdminAuthenticationToken(user, authentication.getCredentials());
        result.setDetails(authentication.getDetails());
        return result;
    }

}

```

