之前的认证方案

回顾一下之前的认证方案

我们的认证是自定义了一个认证处理器JwtAuthenticationTokenFilter,并把他加在了UsernamePasswordAuthenticationFilter过滤器的前面。在过滤器链中我们去掉了UsernamePasswordAuthenticationFilter

登录认证的过程是:

  1. 先经过JwtAuthenticationTokenFilter,查看token。

  2. token为null放行。

  3. 然后进入登录接口/user/login,然后调用了Service层的LoginService

  4. LoginServiceImpl里,实现了认证过程

    调用authenticationManager.authenticate()方法进行认证。

    • 认证成功【UsernamePasswordAuthenticationToken!=null
    1. UsernamePasswordAuthenticationToken中获取UserDetails的实现类LoginUser
    2. Loginuser中获取UserId
    3. 使用Jwt工具类加密userId生成token
    4. Loginuser存储到redis中。
    5. token封装成响应体返回给前端。
    • 认证失败【UsernamePasswordAuthenticationToken==null

    抛出异常。throw new RuntimeException("用户名或密码错误");

注意:我们没有使用UsernamePasswordAuthenticationFilter

另一种认证方案

前置知识

我们将认证成功处理的内容认证失败处理的内容都放在了LoginServiceImpl

而实际上UsernamePasswordAuthenticationFilter过滤器,里面自带了认证成功处理器和认证失败处理器。

1
public class UsernamePasswordAuthenticationFilter extends AbstractAuthenticationProcessingFilter{...}

UsernamePasswordAuthenticationFilter继承了一个抽象的父类AbstractAuthenticationProcessingFilter

我们来看一看其中的doFilter方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
public abstract class AbstractAuthenticationProcessingFilter extends GenericFilterBean implements ApplicationEventPublisherAware, MessageSourceAware {

private AuthenticationSuccessHandler successHandler = new SavedRequestAwareAuthenticationSuccessHandler(); //默认的认证成功处理器
private AuthenticationFailureHandler failureHandler = new
SimpleUrlAuthenticationFailureHandler();//默认的认证失败处理器。
//.....

public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest)req;
HttpServletResponse response = (HttpServletResponse)res;
if (!this.requiresAuthentication(request, response)) {
chain.doFilter(request, response);
} else {
if (this.logger.isDebugEnabled()) {
this.logger.debug("Request is to process authentication");
}

Authentication authResult;
try {
authResult = this.attemptAuthentication(request, response);//获取用户信息Authentication
if (authResult == null) {
return;
}

this.sessionStrategy.onAuthentication(authResult, request, response);
} catch (InternalAuthenticationServiceException var8) {//发生异常--->认证失败
this.logger.error("An internal error occurred while trying to authenticate the user.", var8);
this.unsuccessfulAuthentication(request, response, var8);//调用了认证失败处理方法。
return;
} catch (AuthenticationException var9) {//发生异常--->认证失败
this.unsuccessfulAuthentication(request, response, var9);//调用了认证失败处理方法。
return;
}

if (this.continueChainBeforeSuccessfulAuthentication) {
chain.doFilter(request, response);
}
//能运行到这说明认证成功了
this.successfulAuthentication(request, response, chain, authResult);//调用认证成功处理方法。
}
}
//....

//successfulAuthentication 认证成功处理方法
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException {
//省略...

this.successHandler.onAuthenticationSuccess(request, response, authResult);//调用了认证成功处理器的处理方法。
}
//unsuccessfulAuthentication 认证失败处理方法。
protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) throws IOException, ServletException {
//省略...
this.failureHandler.onAuthenticationFailure(request, response, failed);//调用了认证失败处理器的处理方法。
}
}
  • private AuthenticationSuccessHandler successHandler认证成功处理器接口
  • private AuthenticationFailureHandler failureHandler认证失败处理器接口

思路

实际上在UsernamePasswordAuthenticationFilter进行登录认证的时候

  • 如果登录成功了是会调用AuthenticationSuccessHandler的方法进行认证成功后的处理的。AuthenticationSuccessHandler就是登录成功处理器。
  • 如果认证失败了是会调用AuthenticationFailureHandler的方法进行认证失败后的处理的。AuthenticationFailureHandler就是登录失败处理器。

因此

image-20220822165028412

自定义认证成功处理器

  1. 实现接口AuthenticationSuccessHandler
  2. 注入Spring容器
  3. 撰写方法体
1
2
3
4
5
6
7
8
@Component
public class SGSuccessHandler implements AuthenticationSuccessHandler {

@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
System.out.println("认证成功了");
}
}

自定义认证失败处理器

  1. 实现接口AuthenticationFailureHandler
  2. 注入Spring容器
  3. 撰写方法体
1
2
3
4
5
6
7
@Component
public class SGFailureHandler implements AuthenticationFailureHandler {
@Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
//内容
}
}

最后使用配置类进行配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

@Autowired
private AuthenticationSuccessHandler successHandler;

@Autowired
private AuthenticationFailureHandler failureHandler;

@Override
protected void configure(HttpSecurity http) throws Exception {
http.formLogin()
// 配置认证成功处理器
.successHandler(successHandler)
// 配置认证失败处理器
.failureHandler(failureHandler);

http.authorizeRequests().anyRequest().authenticated();
}
}

登出成功处理器【了解一下即可】

自定义登出成功处理器

  1. 实现接口AuthenticationFailureHandler
  2. 注入Spring容器
  3. 撰写方法体
1
2
3
4
5
6
7
@Component
public class SGLogoutSuccessHandler implements LogoutSuccessHandler {
@Override
public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
System.out.println("注销成功");
}
}

配置

1
2
3
http.logout()
//配置注销成功处理器
.logoutSuccessHandler(logoutSuccessHandler);

__END__