Loading

Spring Security

完整认证与授权流程

请求进入
    ↓
CorsFilter (处理跨域)
    ↓
LogoutFilter (处理退出请求)
    ↓
JwtAuthenticationTokenFilter (手动实现:解析并验证 Token)
    ↓
  ├── Token 有效 ➔ 构建 Authentication 对象并存入 SecurityContextHolder
  └── Token 无效或过期 ➔ 抛出异常,由 ExceptionTranslationFilter 处理
    ↓
ExceptionTranslationFilter (处理认证/授权异常)
    ↓
FilterSecurityInterceptor (自动配置:执行最终权限校验)
    ↓
  ├── 权限足够 ➔ 访问目标资源
  └── 权限不足 ➔ 抛出 AccessDeniedException,由 ExceptionTranslationFilter 处理

总结

  • 无需手动编写FilterSecurityInterceptor 由 Spring Security 自动创建,开发者只需通过 .authorizeHttpRequests() 配置权限规则。
  • 需手动实现:JWT 解析过滤器(JwtAuthenticationTokenFilter)、Token 管理逻辑(TokenService)及异常处理器(AuthenticationEntryPoint)。
  • Token 过期处理:在 TokenService 中校验 exp 时间,抛出异常后由全局异常处理器响应 401,客户端需重新登录或刷新 Token。

Spring Security 的核心原理

以下是 Spring Security 的核心原理与使用方式的逐步解析:


1. 核心流程:过滤器链的拦截机制

Spring Security 的核心是一系列过滤器链,每个过滤器负责不同的安全任务:

  • 请求拦截:所有 HTTP 请求会依次通过过滤器链中的每个过滤器。
    • 示例:访问 /login 时,UsernamePasswordAuthenticationFilter 会拦截表单提交的用户名密码。
  • 关键过滤器
    • SecurityContextPersistenceFilter:从 Session 或请求头中加载用户认证信息(如 Token)。
    • UsernamePasswordAuthenticationFilter:处理表单登录请求,生成未认证的 Authentication 对象。
    • FilterSecurityInterceptor:最终检查用户是否有权限访问资源。
  • 异常处理ExceptionTranslationFilter 捕获认证或权限异常,返回 401 或 403 错误。

2. 认证流程详解

认证(Authentication)是验证用户身份的过程:

  1. 用户提交凭证:通过表单、Token(如 JWT)等方式提交用户名、密码或其他凭证。
  2. 创建 Authentication 对象
    // 示例:表单登录创建 Authentication 对象
    Authentication authRequest = new UsernamePasswordAuthenticationToken(username, password);
    
  3. 调用 AuthenticationManager
    • AuthenticationManager 是认证入口,会调用具体的 AuthenticationProvider(如 DaoAuthenticationProvider)进行验证。
  4. 加载用户信息
    • UserDetailsService 从数据库或缓存中查询用户信息(如密码、权限),返回 UserDetails 对象。
  5. 密码校验
    • 使用 PasswordEncoder(如 BCrypt)对比用户输入的密码和存储的加密密码是否一致。
  6. 存储认证信息
    • 认证成功后,Authentication 对象存入 SecurityContextHolder,供后续授权使用。

3. 授权流程(Authorization)

授权是检查用户是否有权访问资源的过程:

  1. 权限定义
    • 基于 URL:在配置类中定义路径规则,如 .antMatchers("/admin/**").hasRole("ADMIN")
    • 基于注解:在方法上使用 @PreAuthorize("hasAuthority('DELETE_USER')") 动态校验权限。
  2. 权限决策
    • AccessDecisionManager 调用投票器(如 RoleVoter),根据用户的权限集合(GrantedAuthority)决定是否放行。
  3. 异常处理
    • 若权限不足,抛出 AccessDeniedException,由 ExceptionTranslationFilter 处理为 403 响应。

4. RBAC 模型的实现

RBAC(基于角色的访问控制)是常用的权限模型:

  • 数据库设计
    • 用户表(User)、角色表(Role)、权限表(Permission),通过关联表(user_role、role_permission)建立多对多关系。
  • 权限加载
    • 自定义 UserDetailsService,从数据库查询用户的角色和权限,封装到 UserDetails 中。
    // 示例:从数据库加载用户权限
    UserDetails user = userRepository.findByUsername(username);
    user.getRoles().forEach(role -> authorities.add(new SimpleGrantedAuthority(role.getName())));
    
  • 动态控制
    • 在方法上使用 @PreAuthorize 注解,结合 SpEL 表达式动态校验权限:
    @PreAuthorize("hasRole('ADMIN') or #userId == authentication.principal.id")
    public void updateUser(Long userId) { ... }
    

5. 扩展功能示例

(1) 自定义认证方式(如手机验证码登录)

  1. 自定义 UserDetails
    public class PhoneUserDetails implements UserDetails { ... }
    
  2. 自定义 Authentication 对象
    public class PhoneAuthenticationToken extends AbstractAuthenticationToken { ... }
    
  3. 自定义 AuthenticationProvider
    public class PhoneAuthenticationProvider implements AuthenticationProvider {
        public Authentication authenticate(Authentication auth) {
            String phone = auth.getPrincipal().toString();
            String code = auth.getCredentials().toString();
            // 校验验证码并加载用户信息
        }
    }
    
  4. 注册自定义 Provider
    @Bean
    public AuthenticationProvider phoneAuthenticationProvider() {
        return new PhoneAuthenticationProvider();
    }
    

(2) JWT 集成

  1. 生成 Token
    String token = Jwts.builder().setSubject(username).signWith(secretKey).compact();
    
  2. 解析 Token
    Claims claims = Jwts.parser().setSigningKey(secretKey).parseClaimsJws(token).getBody();
    
  3. 自定义 JWT 过滤器
    public class JwtFilter extends OncePerRequestFilter {
        protected void doFilterInternal(...) {
            String token = request.getHeader("Authorization");
            // 解析 Token 并设置到 SecurityContext
        }
    }
    

6. 核心组件总结

组件 作用
SecurityContextHolder 存储当前用户的认证信息(如 Token、角色)
AuthenticationManager 协调认证流程,调用具体的 AuthenticationProvider
UserDetailsService 从数据库或其他数据源加载用户信息
AccessDecisionManager 根据用户权限和资源规则决定是否授权
FilterChainProxy 管理所有过滤器链,处理 HTTP 请求的安全逻辑

7. 适用场景与最佳实践

  • 适用场景
    • 企业级系统(如 OA、CRM)的权限分层管理。
    • 微服务架构中的无状态认证(如 JWT + OAuth2)。
  • 最佳实践
    • 使用 BCryptPasswordEncoder 加密密码。
    • 通过 @EnableGlobalMethodSecurity 启用方法级权限控制。
    • 定期审计权限分配,避免过度授权。

通过以上步骤,可以逐步理解 Spring Security 的工作原理。如需更深入的代码示例或调试技巧,可参考各章节引用的源码和文档链接。

posted @ 2025-05-07 15:23  我不想学编丿程  阅读(51)  评论(0)    收藏  举报