Spring Security: 认证流程详解

一、Spring Security 认证流程原理

1. 认证与授权流程概览

Spring Security 的认证和授权基于**过滤器链(Filter Chain)**实现。请求到达应用后,会依次经过多个过滤器,最终由 AuthenticationManager 完成认证,AccessDecisionManager 完成授权。核心流程如下:

  1. 请求拦截:通过 FilterChainProxy 代理调用多个过滤器(如 UsernamePasswordAuthenticationFilter)。

  2. 认证处理:过滤器将请求中的认证信息(如用户名、密码)封装为 AuthenticationToken,提交给 AuthenticationManager

  3. 身份校验AuthenticationManager 委托具体的 AuthenticationProvider(如 DaoAuthenticationProvider)进行校验,后者通过 UserDetailsService 从数据库加载用户信息并比对密码。

  4. 上下文存储:认证成功后,SecurityContextHolder 存储用户的 SecurityContext(包含认证信息)。

  5. 授权决策FilterSecurityInterceptor 调用 AccessDecisionManager,根据用户权限决定是否允许访问资源。


2. 核心过滤器链

Spring Security 的过滤器链是认证与授权的核心载体,关键组件如下:

过滤器名称作用
SecurityContextPersistenceFilter从 SecurityContextRepository 加载/保存 SecurityContext,确保请求间上下文共享。
UsernamePasswordAuthenticationFilter拦截 /login 请求,处理表单登录,封装 UsernamePasswordAuthenticationToken
BasicAuthenticationFilter处理 HTTP Basic 认证(浏览器弹窗登录)。
RememberMeAuthenticationFilter实现“记住我”功能,基于 Cookie 自动登录。
AnonymousAuthenticationFilter处理匿名请求,为未登录用户分配匿名身份。
ExceptionTranslationFilter捕获认证和授权异常,如 AuthenticationException 和 AccessDeniedException
FilterSecurityInterceptor最终授权决策,调用 AccessDecisionManager 判断用户是否有权限访问资源。

3. 关键概念解析

  • AuthenticationToken
    认证请求的载体,例如 UsernamePasswordAuthenticationToken 封装了用户名和密码。

  • AuthenticationManager
    认证入口,代理多个 AuthenticationProvider,默认实现为 ProviderManager

  • AuthenticationProvider
    具体认证逻辑的实现者(如 DaoAuthenticationProvider 用于数据库校验,CasAuthenticationProvider 用于单点登录)。

  • UserDetailsService
    从数据源(数据库、内存等)加载用户信息,返回 UserDetails 对象(包含用户名、密码、权限列表)。

  • SecurityContext
    存储当前用户的认证信息,通过 SecurityContextHolder 与线程绑定,全局可访问。

二、Spring Security 认证实现步骤

1. 自定义 UserDetailsService

从内存切换为数据库存储用户信息,需实现 UserDetailsService 接口:

@Service
public class UserDetailServiceImpl implements UserDetailsService {
    @Autowired
    private UserMapper userMapper;

    @Override
    public UserDetails loadUserByUsername(String username) {
        User userFromDB = userMapper.selectByUsername(username);
        if (userFromDB == null) {
            throw new UsernameNotFoundException("用户不存在");
        }
        // 从数据库加载权限列表
        List<GrantedAuthority> authorities = new ArrayList<>();
        return new org.springframework.security.core.userdetails.User(
            username, 
            userFromDB.getPassword(), 
            authorities
        );
    }
}

2. 配置密码编码器

明文密码不安全!使用 BCryptPasswordEncoder 加密:

@Bean
public PasswordEncoder passwordEncoder() {
    return new BCryptPasswordEncoder();

3. 集成 MyBatis 

添加依赖: 

 <dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
</dependency>

 配置数据源

spring:
  datasource:
    url: jdbc:mysql:///auth-db
    username: root
    password: 123456
    driver-class-name: com.mysql.cj.jdbc.Driver
mybatis:
  mapper-locations: classpath:mapper/*.xml

4. 自定义登录页面 

 HTML 页面login.html):

<form method="post" action="/login">
    <input type="text" name="username" placeholder="用户名">
    <input type="password" name="password" placeholder="密码">
    <button type="submit">登录</button>
</form>

Spring Security 配置

@Override
protected void configure(HttpSecurity http) throws Exception {
    http.csrf().disable()
        .authorizeRequests()
            .antMatchers("/login.html").permitAll()
            .anyRequest().authenticated()
        .and()
        .formLogin()
            .loginPage("/login.html")
            .loginProcessingUrl("/login")
            .successForwardUrl("/home");
}

三、注意事项与最佳实践

  1. 密码安全:务必使用 BCryptPasswordEncoder 加密,避免明文存储。

  2. 权限控制:通过 @PreAuthorize 或配置类中的 .hasRole() 实现细粒度授权。

  3. 会话管理:启用 HttpSession 管理或结合 Redis 实现分布式会话。

  4. 异常处理:自定义 AuthenticationEntryPoint 和 AccessDeniedHandler 优化异常响应。


四、总结

通过本文,您已掌握 Spring Security 的认证流程原理与实现方法。关键步骤包括:

  • 理解过滤器链与核心组件(如 AuthenticationManagerUserDetailsService)。

  • 实现数据库驱动的用户认证。

  • 配置密码编码器与自定义登录页面。

进一步学习建议:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值