程序员scholar 程序员scholar
首页
  • Java 基础

    • JavaSE
    • JavaIO
    • JavaAPI速查
  • Java 高级

    • JUC
    • JVM
    • Java新特性
    • 设计模式
  • Web 开发

    • Servlet
    • Java网络编程
  • 数据结构
  • HTTP协议
  • HTTPS协议
  • 计算机网络
  • Linux常用命令
  • Windows常用命令
  • SQL数据库

    • MySQL
    • MySQL速查
  • NoSQL数据库

    • Redis
    • ElasticSearch
  • 数据库

    • MyBatis
    • MyBatis-Plus
  • 消息中间件

    • RabbitMQ
  • 服务器

    • Nginx
  • Python 基础

    • Python基础
  • Python 进阶

    • 装饰器与生成器
    • 异常处理
    • 标准库精讲
    • 模块与包
    • pip包管理工具
  • Spring框架

    • Spring6
    • SpringMVC
    • SpringBoot
    • SpringSecurity
  • SpringCould微服务

    • SpringCloud基础
    • 微服务之DDD架构思想
  • 日常必备

    • 开发常用工具包
    • Hutoll工具包
    • IDEA常用配置
    • 开发笔记
    • 日常记录
    • 项目部署
    • 网站导航
    • 产品学习
    • 英语学习
  • 代码管理

    • Maven
    • Git教程
    • Git小乌龟教程
  • 运维工具

    • Docker
    • Jenkins
    • Kubernetes
前端 (opens new window)
  • 算法笔记

    • 算法思想
    • 刷题笔记
  • 面试问题常见

    • 十大经典排序算法
    • 面试常见问题集锦
关于
GitHub (opens new window)
首页
  • Java 基础

    • JavaSE
    • JavaIO
    • JavaAPI速查
  • Java 高级

    • JUC
    • JVM
    • Java新特性
    • 设计模式
  • Web 开发

    • Servlet
    • Java网络编程
  • 数据结构
  • HTTP协议
  • HTTPS协议
  • 计算机网络
  • Linux常用命令
  • Windows常用命令
  • SQL数据库

    • MySQL
    • MySQL速查
  • NoSQL数据库

    • Redis
    • ElasticSearch
  • 数据库

    • MyBatis
    • MyBatis-Plus
  • 消息中间件

    • RabbitMQ
  • 服务器

    • Nginx
  • Python 基础

    • Python基础
  • Python 进阶

    • 装饰器与生成器
    • 异常处理
    • 标准库精讲
    • 模块与包
    • pip包管理工具
  • Spring框架

    • Spring6
    • SpringMVC
    • SpringBoot
    • SpringSecurity
  • SpringCould微服务

    • SpringCloud基础
    • 微服务之DDD架构思想
  • 日常必备

    • 开发常用工具包
    • Hutoll工具包
    • IDEA常用配置
    • 开发笔记
    • 日常记录
    • 项目部署
    • 网站导航
    • 产品学习
    • 英语学习
  • 代码管理

    • Maven
    • Git教程
    • Git小乌龟教程
  • 运维工具

    • Docker
    • Jenkins
    • Kubernetes
前端 (opens new window)
  • 算法笔记

    • 算法思想
    • 刷题笔记
  • 面试问题常见

    • 十大经典排序算法
    • 面试常见问题集锦
关于
GitHub (opens new window)
npm

(进入注册为作者充电)

  • SpringSecurity

    • Spring Security是什么
    • 认证与授权的基本概念
    • Spring Security 的默认配置
    • SpringSecurity的默认登录页
    • Spring Security 的 Filter 机制
    • HttpSecurity 与自定义登录页面
    • Spring Security 的核心组件与扩展
    • Spring Security 中的用户认证与角色管理
    • Spring Security 的授权机制与安全表达式
    • Security 的 Session 与 Token 管理
    • Spring Security 集成第三方登录
    • Spring Security 集成 QQ 登录与 JWT 认证
    • Spring Security 登录认证源码
      • 1. 登录校验流程
      • 2. 源码原理初探
      • 3. 源码认证流程详解
        • 1. 认证流程概述
        • 2. 登录请求拦截
        • 默认行为
        • 自定义行为
        • 3. 封装认证令牌
        • 4. 调用 `AuthenticationManager`
        • 5. 调用 `AuthenticationProvider`
        • 6. 加载用户信息
        • 7. 密码校验
        • 8. 认证成功处理
        • 如何获取认证信息
        • 获取认证用户信息
        • 认证信息的结构
        • 获取用户的角色和权限
        • 判断用户是否具有某个角色
        • 9. 认证失败处理
        • 10. 开发者需要自定义的部分
    • Spring Security - JWT认证实战
    • Spring Security - JWT授权实战
    • Spring Security 异常处理与自定义逻辑
  • SpringSecurity
  • SpringSecurity
scholar
2024-12-28
目录

Spring Security 登录认证源码

# Spring Security 登录认证源码


# 1. 登录校验流程

image-20240510123654190


# 2. 源码原理初探

SpringSecurity 的核心机制是一个 过滤器链,它内部包含了多个过滤器,分别提供不同的功能。

在下图,我们可以观察到核心过滤器,如下图所示:

image-20241229163043787

核心过滤器功能解析:

  1. UsernamePasswordAuthenticationFilter
    • 负责处理登录页面提交的用户名和密码。
    • 入门案例中的认证工作主要由这个过滤器完成。
  2. ExceptionTranslationFilter
    • 用于处理过滤器链中抛出的异常,如 AccessDeniedException 和 AuthenticationException。
  3. FilterSecurityInterceptor
    • 负责权限校验。

调试方式:

我们可以通过 Debug 模式 查看当前系统中 SpringSecurity 过滤器链的顺序和种类。

执行以下代码可以获取过滤器链中的过滤器:

run.getBean(DefaultSecurityFilterChain.class);
// 通过断点观察过滤器链
1
2

调试时的过滤器链示例如下:

image-20240510124139924

通过观察,可以清楚了解过滤器链中各个过滤器的顺序和功能。

image-20241222222100794


# 3. 源码认证流程详解

完整的认证流程如下图所示:

image-20240510124630110


# 1. 认证流程概述

Spring Security 登录认证流程是以 过滤器链 为核心,通过一系列组件协作完成用户认证和授权。主要流程如下:

  1. 用户发送登录请求(默认是 /login,也可以自定义)。
  2. 请求被过滤器 UsernamePasswordAuthenticationFilter 拦截。
  3. 用户名和密码被封装为认证令牌 UsernamePasswordAuthenticationToken。
  4. 调用 AuthenticationManager 进行认证。
  5. AuthenticationManager 委托 AuthenticationProvider 验证用户身份。
  6. AuthenticationProvider 调用 UserDetailsService 加载用户信息。
  7. 验证密码是否匹配。
  8. 如果认证成功,将用户信息存储到 SecurityContextHolder。
  9. 如果认证失败,执行失败处理逻辑。

# 2. 登录请求拦截

说明: 当用户提交登录请求时,Spring Security 默认使用 UsernamePasswordAuthenticationFilter 来拦截该请求。

核心源码:

@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
        throws IOException, ServletException {
    HttpServletRequest request = (HttpServletRequest) req;
    HttpServletResponse response = (HttpServletResponse) res;

    // 1. 判断当前请求是否需要进行认证处理
    if (!requiresAuthentication(request, response)) {
        chain.doFilter(request, response);
        return;
    }

    // 2. 提取用户名和密码
    String username = obtainUsername(request); // 默认读取 "username" 参数
    String password = obtainPassword(request); // 默认读取 "password" 参数

    // 3. 封装认证令牌
    UsernamePasswordAuthenticationToken authRequest =
            new UsernamePasswordAuthenticationToken(username, password);

    // 4. 调用认证管理器进行认证
    Authentication authResult;
    try {
        authResult = this.getAuthenticationManager().authenticate(authRequest);
    } catch (AuthenticationException failed) {
        // 认证失败处理
        unsuccessfulAuthentication(request, response, failed);
        return;
    }

    // 5. 认证成功处理
    successfulAuthentication(request, response, chain, authResult);
}
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

详细解析:

  1. 拦截登录请求:
    • 判断当前请求是否需要认证,默认拦截 /login 路径的 POST 请求。
    • 可以通过配置 formLogin().loginPage("/customLogin") 自定义登录路径。
  2. 提取用户名和密码:
    • 默认从请求体中读取 username 和 password 参数。
    • 如果需要自定义参数名,可以重写 obtainUsername 和 obtainPassword 方法。
  3. 封装认证令牌:
    • 使用 UsernamePasswordAuthenticationToken 将用户名和密码封装为认证令牌。
    • 认证令牌的作用是将用户的认证信息传递到后续的认证流程中。
  4. 调用认证管理器:
    • 调用 AuthenticationManager 的 authenticate 方法,开始用户身份验证。
  5. 处理认证结果:
    • 如果认证成功,调用 successfulAuthentication。
    • 如果认证失败,调用 unsuccessfulAuthentication。

# 默认行为

默认情况下,UsernamePasswordAuthenticationFilter 只处理 /login 的请求,但这个行为是可以通过配置进行更改的。

  1. 默认请求路径:
    • UsernamePasswordAuthenticationFilter 的默认请求路径是 /login,并且仅处理 POST 方法。
    • 这个默认路径是 Spring Security 预设的,符合大多数场景下的登录请求需求。
  2. 认证逻辑:
    • 当客户端向 /login 提交用户名和密码时,UsernamePasswordAuthenticationFilter 会尝试从请求中提取这两个参数,并调用 AuthenticationManager 进行认证。
    • 认证成功后,它会将用户的 Authentication 信息存储到 SecurityContextHolder,并返回认证成功的响应。
  3. 适配表单登录:
    • UsernamePasswordAuthenticationFilter 默认用于处理基于表单的登录请求。

# 自定义行为

如果需要自定义 UsernamePasswordAuthenticationFilter 的行为,例如更改登录路径或处理其他请求,你可以通过以下方式实现,使用 Spring Security 配置类改变过滤器处理的路径:

@Override
protected void configure(HttpSecurity http) throws Exception {
    http
        .formLogin()
        .loginProcessingUrl("/custom-login") // 改为自定义路径
        .permitAll();
}
1
2
3
4
5
6
7
  • loginProcessingUrl() 方法可以更改 UsernamePasswordAuthenticationFilter 处理的路径。

# 3. 封装认证令牌

说明: 认证令牌是 Spring Security 的核心组件之一,用于封装用户的认证信息。在默认登录认证流程中,UsernamePasswordAuthenticationToken 是最常用的认证令牌。

核心源码:

public class UsernamePasswordAuthenticationToken extends AbstractAuthenticationToken {
    private final Object principal; // 用户名
    private Object credentials;     // 密码

    public UsernamePasswordAuthenticationToken(Object principal, Object credentials) {
        super(null);
        this.principal = principal;
        this.credentials = credentials;
        setAuthenticated(false); // 初始状态为未认证
    }
}
1
2
3
4
5
6
7
8
9
10
11

详细解析:

  1. principal:用户标识信息,通常是用户名。
  2. credentials:用户凭证,通常是密码。
  3. 初始状态:令牌创建时 setAuthenticated(false),表示未认证状态。

# 4. 调用 AuthenticationManager

说明: AuthenticationManager 是 Spring Security 认证流程的核心接口,其默认实现是 ProviderManager,负责分发认证请求给具体的认证提供者。

核心源码(ProviderManager):
















 















@Override
public Authentication authenticate(Authentication authentication)
        throws AuthenticationException {
    AuthenticationException lastException = null;
    Authentication result = null;

    // 遍历所有注册的 AuthenticationProvider
    for (AuthenticationProvider provider : this.providers) {
        // 判断是否支持当前认证令牌类型
        if (!provider.supports(authentication.getClass())) {
            continue;
        }

        try {
            // 调用具体的 AuthenticationProvider 进行认证
            result = provider.authenticate(authentication);
            if (result != null) {
                return result; // 认证成功
            }
        } catch (AuthenticationException ex) {
            lastException = ex;
        }
    }

    // 如果没有任何 Provider 成功认证,抛出异常
    if (lastException != null) {
        throw lastException;
    }
    throw new ProviderNotFoundException("No AuthenticationProvider found for " + authentication.getClass().getName());
}
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

详细解析:

  1. 分发认证请求:
    • 遍历所有注册的 AuthenticationProvider,找到支持当前认证令牌的提供者。
    • image-20241229130910512
    • 默认情况下,Spring Security 会注册 DaoAuthenticationProvider。
  2. 调用认证提供者:
    • 调用 AuthenticationProvider.authenticate() 方法完成认证。
  3. 认证失败:
    • 如果所有提供者都未能成功认证,抛出 AuthenticationException。

# 5. 调用 AuthenticationProvider

说明: AuthenticationProvider 是认证逻辑的核心组件,负责具体的认证实现。 DaoAuthenticationProvider 是 Spring Security 中最常用的认证提供者,适用于基于用户名和密码的认证。

image-20241229131425208

核心源码(AbstractUserDetailsAuthenticationProvider):

@Override
public Authentication authenticate(Authentication authentication)
        throws AuthenticationException {
    // 提取用户名和密码
    String username = authentication.getName();
    String password = (String) authentication.getCredentials();

    // 调用 UserDetailsService 加载用户信息
    UserDetails user = retrieveUser(username, (UsernamePasswordAuthenticationToken) authentication);

    // 验证密码
    additionalAuthenticationChecks(user, (UsernamePasswordAuthenticationToken) authentication);

    // 认证成功,返回认证后的令牌
    return createSuccessAuthentication(authentication, user);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

详细解析:

  1. 提取用户名和密码:
    • 从认证令牌中提取用户名和密码。
  2. 加载用户信息:
    • 调用 UserDetailsService.loadUserByUsername() 加载用户信息。
  3. 验证密码:
    • 使用 PasswordEncoder.matches() 验证用户输入的密码与数据库中存储的密码是否匹配。
  4. 返回认证结果:
    • 如果用户名和密码验证成功,返回一个新的认证令牌,标记为已认证。

通过AbstractUserDetailsAuthenticationProvider下的retrieveUser方法 进入DaoAuthenticationProvider的实现

image-20241229130316363

image-20241229130422007

# 6. 加载用户信息

默认加载用户信息的机制

当没有显式配置 UserDetailsService 时,Spring Security 会默认使用 InMemoryUserDetailsManager 来加载用户信息。InMemoryUserDetailsManager 是一个实现了 UserDetailsService 接口的类,它会将用户信息存储在内存中,适用于小型应用或开发环境。

源码解析:InMemoryUserDetailsManager

InMemoryUserDetailsManager 是 Spring Security 提供的一个简单实现,它将用户信息保存在内存中的一个 Map 里。下面是 InMemoryUserDetailsManager 的关键部分代码:

public class InMemoryUserDetailsManager implements UserDetailsService {

    private final Map<String, UserDetails> users = new HashMap<>();

    // 默认的构造函数,加载一些内存中的用户
    public InMemoryUserDetailsManager(UserDetails... users) {
        for (UserDetails user : users) {
            this.users.put(user.getUsername(), user);
        }
    }

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        UserDetails user = users.get(username);
        if (user == null) {
            throw new UsernameNotFoundException("User not found with username: " + username);
        }
        return user;
    }

    // 添加或更新用户
    public void createUser(UserDetails user) {
        users.put(user.getUsername(), user);
    }

    // 删除用户
    public void deleteUser(String username) {
        users.remove(username);
    }

    // 更新用户
    public void updateUser(UserDetails user) {
        users.put(user.getUsername(), user);
    }
}
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

如何启用内存用户管理

默认情况下,Spring Security 会自动启用 InMemoryUserDetailsManager,如果你没有配置任何 UserDetailsService,它会使用该类作为用户加载的实现。你可以通过 AuthenticationManagerBuilder 配置用户信息,以下是一个例子:

 org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;

@Configuration
@EnableWebSecurity
public class SecurityConfig {

    // 配置 HTTP 安全性
    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
                .antMatchers("/admin/**").hasRole("ADMIN")  // 限制/admin/**路径访问权限
                .antMatchers("/user/**").hasRole("USER")    // 限制/user/**路径访问权限
                .anyRequest().authenticated()  // 其他所有路径都需要认证
            .and()
            .formLogin()
                .permitAll();  // 允许所有用户访问登录页面

        return http.build();
    }

    // 配置认证管理器
    @Bean
    public AuthenticationManager authenticationManager(HttpSecurity http) throws Exception {
        AuthenticationManagerBuilder authenticationManagerBuilder = 
                http.getSharedObject(AuthenticationManagerBuilder.class);

        authenticationManagerBuilder
            .inMemoryAuthentication()
                .passwordEncoder(passwordEncoder())  // 使用密码加密器
                .withUser("user").password("{noop}password").roles("USER")  // 定义用户 user 和密码
                .and()
                .withUser("admin").password("{noop}admin").roles("ADMIN");  // 定义用户 admin 和密码

        return authenticationManagerBuilder.build();
    }

    // 密码加密器配置
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();  // 使用 BCrypt 加密密码
    }
}
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
  • 通过 http.getSharedObject(AuthenticationManagerBuilder.class) 获取 AuthenticationManagerBuilder 实例。
  • inMemoryAuthentication() 表示使用内存中的用户存储。
  • passwordEncoder(passwordEncoder()) 用于配置密码加密器,这里使用 BCryptPasswordEncoder。
  • withUser("user").password("{noop}password").roles("USER") 用于创建用户名为 user 的用户,并指定其密码为 password,角色为 USER。{noop} 表示不使用密码编码器,即密码为明文。
  • 同样,创建用户名为 admin 的用户,并指定其角色为 ADMIN。

内存加载的局限性

  • 适用场景:InMemoryUserDetailsManager 适用于一些简单场景,比如原型开发、原型测试、或者小型应用的快速启动。在这种情况下,用户数据是硬编码在配置中的,并且存储在 JVM 内存中。
  • 数据持久性:使用 InMemoryUserDetailsManager 的数据并不会持久化存储。即使应用重启,所有的用户数据都会丢失。对于大规模应用或者生产环境,通常需要使用数据库来存储用户信息。

总结

  • 默认行为:Spring Security 默认提供 InMemoryUserDetailsManager 来加载用户信息,这意味着在没有显式配置 UserDetailsService 的情况下,它会在内存中管理用户信息。
  • 用法:你可以使用 AuthenticationManagerBuilder 来配置内存中的用户,或者在其他地方自定义 InMemoryUserDetailsManager。
  • 适用场景:适用于快速开发、测试或小型应用,不适用于生产环境。

如果你需要持久化存储用户信息(如从数据库加载用户信息),则可以实现 UserDetailsService 接口,并将其配置到 Spring Security 中。


# 7. 密码校验

说明: Spring Security 提供了 PasswordEncoder 接口,用于对密码进行加密和匹配验证。默认使用 BCryptPasswordEncoder。

源码解析(密码校验):

@Override
protected void additionalAuthenticationChecks(UserDetails userDetails, UsernamePasswordAuthenticationToken authentication)
        throws AuthenticationException {
    if (authentication.getCredentials() == null) {
        throw new BadCredentialsException("Bad credentials");
    }
    String presentedPassword = authentication.getCredentials().toString();
    if (!passwordEncoder.matches(presentedPassword, userDetails.getPassword())) {
        throw new BadCredentialsException("Bad credentials");
    }
}
1
2
3
4
5
6
7
8
9
10
11

# 8. 认证成功处理

说明: 当用户成功通过认证(例如,用户名和密码验证、JWT 验证等),Spring Security 会将认证信息存储在 SecurityContextHolder 中。SecurityContextHolder 是一个静态容器,它用于存储当前线程中的安全上下文,主要包含 Authentication 对象,该对象存储了当前认证用户的详细信息(如用户名、角色、权限等)。

源码解析:

protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response,
                                         FilterChain chain, Authentication authResult)
        throws IOException, ServletException {
    // 将认证结果(用户信息)存储到 SecurityContextHolder
    SecurityContextHolder.getContext().setAuthentication(authResult);
    
    // 调用成功处理器,执行认证成功后的逻辑,如生成JWT、跳转页面等
    successHandler.onAuthenticationSuccess(request, response, authResult);
}
1
2
3
4
5
6
7
8
9

# 如何获取认证信息

认证成功后,Spring Security 会将认证信息存储到 SecurityContextHolder 中。你可以从 SecurityContextHolder 中获取当前用户的认证信息,通常通过 Authentication 对象来访问。

获取 Authentication 对象

Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
1

Authentication 对象是当前认证的核心,里面包含了用户的认证信息,如 Principal(用户信息)、Authorities(角色/权限)等。

# 获取认证用户信息

Authentication.getPrincipal() 返回的是当前用户的主体信息,通常是实现了 UserDetails 接口的对象。

// 获取 `Authentication` 对象
public static Authentication getAuthentication() {
    return SecurityContextHolder.getContext().getAuthentication();
}

public static LoginUser getLoginUser() {
    try {
        // 返回当前认证用户的主体信息,通常是 `UserDetails` 的实现类
        return (LoginUser) getAuthentication().getPrincipal();
    } catch (Exception e) {
        // 异常处理,如果获取用户信息失败,抛出自定义异常
        throw new ServiceException("获取用户信息异常", HttpStatus.UNAUTHORIZED);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# 认证信息的结构

Authentication 对象是 Spring Security 中的核心接口,包含了用户的各种信息,主要字段如下:

  • getPrincipal():返回当前认证用户的主体信息,通常是 UserDetails 的实现类。
  • getAuthorities():返回当前用户的权限(角色)。
  • getCredentials():返回用户的凭据(例如密码),通常认证成功后,凭据就不会再被使用。
  • getDetails():返回与认证相关的附加信息。
  • isAuthenticated():判断当前用户是否已经认证。

# 获取用户的角色和权限

Authentication.getAuthorities() 返回的是用户的权限(或角色)。它是一个 Collection<? extends GrantedAuthority> 类型,通常是用户的角色。

public static Collection<? extends GrantedAuthority> getAuthorities() {
    return getAuthentication().getAuthorities();
}
1
2
3

你可以遍历该集合,获取用户的所有角色或权限。

例如,获取当前用户的所有角色:

public static List<String> getRoles() {
    Collection<? extends GrantedAuthority> authorities = getAuthorities();
    return authorities.stream()
                      .map(GrantedAuthority::getAuthority)
                      .collect(Collectors.toList());
}
1
2
3
4
5
6

# 判断用户是否具有某个角色

你可以通过 Authentication.getAuthorities() 获取当前用户的角色,然后判断用户是否具有某个特定角色。例如:

public static boolean hasRole(String role) {
    Collection<? extends GrantedAuthority> authorities = getAuthorities();
    return authorities.stream()
                      .anyMatch(authority -> authority.getAuthority().equals(role));
}
1
2
3
4
5

# 9. 认证失败处理

说明: 如果认证失败,Spring Security 会调用失败处理器返回错误响应。

源码解析:

protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response,
                                           AuthenticationException failed)
        throws IOException, ServletException {
    failureHandler.onAuthenticationFailure(request, response, failed);
}
1
2
3
4
5

# 10. 开发者需要自定义的部分

  1. 实现 UserDetailsService 加载用户信息。
  2. 配置 PasswordEncoder 用于加密和匹配密码。
  3. 可选:自定义登录页面和认证成功/失败处理逻辑。
编辑此页 (opens new window)
上次更新: 2024/12/29, 23:35:48
Spring Security 集成 QQ 登录与 JWT 认证
Spring Security - JWT认证实战

← Spring Security 集成 QQ 登录与 JWT 认证 Spring Security - JWT认证实战→

Theme by Vdoing | Copyright © 2019-2025 程序员scholar
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式