当前位置: 首页 > java >正文

Spring Security 认证流程——补充

一、认证流程概述

Spring Security 的认证流程基于 过滤器链(Filter Chain),核心组件包括 UsernamePasswordAuthenticationFilterAuthenticationManagerUserDetailsService 等。整个流程可分为以下步骤:

  1. 用户提交登录请求
  2. 拦截请求并封装认证对象
  3. 认证管理器(AuthenticationManager)处理认证
  4. 认证成功或失败的处理
  5. 安全上下文存储与后续处理

二、详细步骤解析

1. 用户提交登录请求

  • 用户通过表单提交用户名和密码(如访问 /login 路径)。
  • 请求由 UsernamePasswordAuthenticationFilter 拦截(默认处理 /login 请求)。

2. 拦截请求并封装认证对象

  • UsernamePasswordAuthenticationFilter 的作用
    • 从请求中提取用户名和密码。
    • 创建 UsernamePasswordAuthenticationToken 对象(未认证的 Authentication 实例)。
    • 示例代码:
public class UsernamePasswordAuthenticationFilter extends AbstractAuthenticationProcessingFilter {public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) {String username = obtainUsername(request); // 提取用户名String password = obtainPassword(request); // 提取密码UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password);return this.getAuthenticationManager().authenticate(authRequest); // 调用认证管理器}
}

3. 认证管理器(AuthenticationManager)处理认证

  • AuthenticationManager 的职责
    • 协调认证流程,调用 AuthenticationProvider 进行具体认证。
    • 默认实现是 ProviderManager,其内部维护一个 AuthenticationProvider 列表。
  • DaoAuthenticationProvider 的角色
    • 负责从数据源加载用户信息(通过 UserDetailsService)。
    • 对比用户输入的密码与数据库中存储的密码(通过 PasswordEncoder)。
    • 示例代码:
public class DaoAuthenticationProvider implements AuthenticationProvider {@Overridepublic Authentication authenticate(Authentication authentication) {String username = authentication.getName();UserDetails userDetails = userDetailsService.loadUserByUsername(username); // 加载用户信息if (passwordEncoder.matches(authentication.getCredentials().toString(), userDetails.getPassword())) {return new UsernamePasswordAuthenticationToken(userDetails, authentication.getCredentials(), userDetails.getAuthorities());} else {throw new BadCredentialsException("密码错误");}}
}

4. 认证成功或失败的处理

  • 认证成功

    • AuthenticationManager 返回已认证的 Authentication 对象。
    • UsernamePasswordAuthenticationFilter 将该对象存入 SecurityContextHolder(通过 SecurityContext)。
    • 触发 AuthenticationSuccessHandler(如跳转到首页或返回 JWT 令牌)。
    • 示例代码:
public class UsernamePasswordAuthenticationFilter {private AuthenticationSuccessHandler successHandler;protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, Authentication authResult) {SecurityContextHolder.getContext().setAuthentication(authResult); // 存储认证信息successHandler.onAuthenticationSuccess(request, response, authResult); // 调用成功处理器}
}

认证失败

  • AuthenticationManager 抛出 AuthenticationException 异常。
  • UsernamePasswordAuthenticationFilter 调用 AuthenticationFailureHandler(如返回错误信息或重定向到登录页面)。
  • 示例代码:
public class UsernamePasswordAuthenticationFilter {private AuthenticationFailureHandler failureHandler;protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) {failureHandler.onAuthenticationFailure(request, response, failed); // 调用失败处理器}
}

5. 安全上下文存储与后续处理

  • SecurityContextPersistenceFilter 的作用
    • 在请求开始时,从 SecurityContextRepository(默认是 HttpSessionSecurityContextRepository)加载 SecurityContext 到当前线程。
    • 在请求结束时,将 SecurityContext 保存回 SecurityContextRepository 并清空线程中的上下文。
    • 示例代码:
public class SecurityContextPersistenceFilter implements Filter {public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) {HttpServletRequest request = (HttpServletRequest) req;HttpSession session = request.getSession(false);SecurityContext context = session != null ? (SecurityContext) session.getAttribute("SPRING_SECURITY_CONTEXT") : null;SecurityContextHolder.setContext(context); // 加载上下文try {chain.doFilter(req, res);} finally {session = ((HttpServletRequest) req).getSession(false);session.setAttribute("SPRING_SECURITY_CONTEXT", SecurityContextHolder.getContext()); // 保存上下文SecurityContextHolder.clearContext(); // 清空线程上下文}}
}

三、关键组件与接口

组件/接口职责
Authentication封装用户凭证(如用户名、密码)和权限信息。
AuthenticationManager认证入口,协调多个 AuthenticationProvider
AuthenticationProvider具体认证逻辑的实现者(如 DaoAuthenticationProvider)。
UserDetailsService从数据源加载用户信息(如数据库),返回 UserDetails 对象。
PasswordEncoder加密和校验密码(如 BCryptPasswordEncoder)。
SecurityContext存储当前用户的认证信息(通过 SecurityContextHolder 与线程绑定)。

四、认证流程图

[用户提交登录请求]↓
[UsernamePasswordAuthenticationFilter 拦截请求]↓
[创建 UsernamePasswordAuthenticationToken(未认证)]↓
[调用 AuthenticationManager.authenticate()]↓
[ProviderManager 遍历 AuthenticationProvider]↓
[DaoAuthenticationProvider 加载用户信息(通过 UserDetailsService)]↓
[PasswordEncoder 校验密码]↓
[认证成功:返回已认证的 Authentication 对象]↓
[SecurityContextHolder 存储 Authentication]↓
[调用 AuthenticationSuccessHandler(如跳转页面或返回 JWT)]

五、自定义认证逻辑

  • 自定义 UserDetailsService

    • 实现 UserDetailsService 接口,从数据库加载用户信息。
    • 示例代码:
@Service
public class CustomUserDetailsService implements UserDetailsService {@Autowiredprivate UserRepository userRepository;@Overridepublic UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {User user = userRepository.findByUsername(username);if (user == null) {throw new UsernameNotFoundException("用户不存在");}return new org.springframework.security.core.userdetails.User(user.getUsername(),user.getPassword(),AuthorityUtils.createAuthorityList("ROLE_USER") // 返回用户权限);}
}

自定义 PasswordEncoder

  • 使用 BCryptPasswordEncoder 或自定义加密逻辑。
  • 示例代码:
@Bean
public PasswordEncoder passwordEncoder() {return new BCryptPasswordEncoder();
}

六、常见问题与解决方案

  • 密码不匹配

    • 确保 UserDetailsService 返回的密码与数据库中存储的密码格式一致(如已加密)。
    • 检查 PasswordEncoder 配置是否正确。
  • 认证失败无提示

    • 自定义 AuthenticationFailureHandler 处理异常,返回用户友好的错误信息。
  • 多认证方式支持

    • 添加自定义过滤器(如 JWT 认证过滤器),插入到过滤器链中。
    • 示例配置:
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {@Overrideprotected void configure(HttpSecurity http) throws Exception {http.addFilterBefore(new JwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);}
}

七、总结

Spring Security 的认证流程通过 过滤器链核心组件协作 实现,关键步骤包括:

  1. 用户提交登录请求,被 UsernamePasswordAuthenticationFilter 拦截。
  2. AuthenticationManager 协调 AuthenticationProvider 进行认证。
  3. UserDetailsService 加载用户信息,PasswordEncoder 校验密码。
  4. 认证结果通过 SecurityContext 存储,并触发成功或失败处理器。

掌握这一流程后,开发者可以灵活配置认证逻辑(如数据库认证、JWT 认证)并扩展安全功能(如动态权限控制)

http://www.xdnf.cn/news/13011.html

相关文章:

  • 5G 智慧工业园区解决方案
  • 多元隐函数 偏导公式
  • 跨链模式:多链互操作架构与性能扩展方案
  • 06 Deep learning神经网络编程基础 激活函数 --吴恩达
  • 基于深度学习的图像分割技术:原理、应用与实践
  • Citation引证/Equilateral Triangle等边三角形/ 字符串旋转/F.小红的区间修改(二)
  • ip子接口配置及删除
  • USB Over IP专用硬件的5个特点
  • webpack打包vue项目
  • 【大厂机试题解法笔记】食堂供餐
  • 进程间通信详解(一):管道机制与实现原理
  • PP-OCRv5 ubuntu20.04 OCR识别服务
  • 第三章 3.1 传感器安全
  • 代码随想录刷题day30
  • Invalid context structure解决Dify框架中图像推理错误:一步步排查与修复指南
  • 相机从app启动流程
  • helm使用说明和实例
  • 数据库分批入库
  • Vue 模板语句的数据来源
  • linux之 内存管理(6)-arm64 内核虚拟地址空间变化
  • Conda安装pytorch和cuda出现问题的解决记录
  • pikachu靶场通关笔记22-1 SQL注入05-1-insert注入(报错法)
  • Java多线程实现之Thread类深度解析
  • 【Kafka】Kafka从入门到实战:构建高吞吐量分布式消息系统
  • GeoDrive:基于三维几何信息有精确动作控制的驾驶世界模型
  • 快速使用 Flutter 的 Dialog 和 AlertDialog
  • Delivering Arbitrary-Modal Semantic Segmentation(CVPR2023)任意模态语义分割论文阅读
  • 基于Uniapp开发HarmonyOS 5.0旅游应用技术实践
  • 如何把工业通信协议转换成http websocket
  • MongoDB 入门指南:安装、配置与 Navicat 连接教程