找回密码
 立即注册
首页 业界区 业界 Spring Security 鉴权流程与过滤器链深度剖析 ...

Spring Security 鉴权流程与过滤器链深度剖析

叟澡帅 2025-11-26 17:05:17
一、login接口鉴权流程

1.1 流程概述

login接口是用户认证入口,核心是验证用户名密码并生成JWT Token。流程涉及控制器认证管理器用户服务密码编码器JWT工具过滤器协同工作。
1.2 详细步骤与代码示例

1.2.1 请求接收(Controller层接口)

组件标注:表现层接口(AuthController.login())
  1. @RestController
  2. @RequestMapping("/api/auth")
  3. @RequiredArgsConstructor
  4. public class AuthController {
  5.     private final AuthenticationManager authenticationManager;
  6.     private final JwtUtils jwtUtils;
  7.     @PostMapping("/login")
  8.     public Result<JwtResponse> login(@RequestBody LoginRequest request) {
  9.         Authentication authentication = authenticationManager.authenticate(
  10.             new UsernamePasswordAuthenticationToken(request.getUsername(), request.getPassword())
  11.         );
  12.         UserDetails userDetails = (UserDetails) authentication.getPrincipal();
  13.         String token = jwtUtils.generateToken(userDetails);
  14.         return Result.success(new JwtResponse(token, userDetails.getUsername()));
  15.     }
  16. }
  17. @Data class LoginRequest { private String username; private String password; }
  18. @Data class JwtResponse { private String token; private String username; public JwtResponse(String t, String u) { token=t; username=u; } }
复制代码
1.2.2 触发认证与加载用户信息(Service层)

自定义用户服务实现
  1. @Service
  2. @RequiredArgsConstructor
  3. public class UserDetailsServiceImpl implements UserDetailsService {
  4.     private final UserMapper userMapper;
  5.     private final RoleMapper roleMapper;
  6.     @Override
  7.     public UserDetails loadUserByUsername(String username) {
  8.         UserPo user = userMapper.selectOne(new QueryWrapper<UserPo>().eq("username", username));
  9.         if (user == null) throw new UsernameNotFoundException("用户不存在");
  10.         Set<RolePo> roles = roleMapper.findRolesByUserId(user.getId());
  11.         user.setRoles(roles);
  12.         return user;
  13.     }
  14. }
复制代码
Spring Security认证管理器源码核心逻辑(ProviderManager):
  1. public class ProviderManager implements AuthenticationManager {
  2.     private List providers;
  3.     public Authentication authenticate(Authentication auth) {
  4.         for (AuthenticationProvider p : providers) {
  5.             if (p.supports(auth.getClass())) {
  6.                 Authentication result = p.authenticate(auth);
  7.                 if (result != null) return result;
  8.             }
  9.         }
  10.         throw new AuthenticationException("认证失败") {};
  11.     }
  12. }
复制代码
1.2.3 密码校验(Util层)

配置类代码
  1. @Configuration
  2. public class SecurityConfig {
  3.     @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); }
  4. }
复制代码
密码对比源码核心逻辑(DaoAuthenticationProvider):
  1. public class DaoAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider {
  2.     protected void additionalAuthenticationChecks(UserDetails ud, UsernamePasswordAuthenticationToken auth) {
  3.         String presented = auth.getCredentials().toString();
  4.         String encoded = ud.getPassword();
  5.         if (!passwordEncoder.matches(presented, encoded)) throw new BadCredentialsException("密码错误");
  6.     }
  7. }
复制代码
BCryptPasswordEncoder源码核心逻辑
  1. public class BCryptPasswordEncoder implements PasswordEncoder {
  2.     public boolean matches(CharSequence raw, String encoded) {
  3.         BCrypt.HashData hashData = decode(encoded);
  4.         byte[] hashed = BCrypt.hashpw(raw.toString(), hashData);
  5.         return constantTimeEquals(hashed, hashData.password);
  6.     }
  7. }
复制代码
1.2.4 生成JWT Token(Util层)

JWT工具类代码
  1. @Component
  2. public class JwtUtils {
  3.     @Value("${app.jwt.secret}") private String secret;
  4.     @Value("${app.jwt.expiration}") private long expiration;
  5.     public String generateToken(UserDetails ud) {
  6.         return Jwts.builder().setSubject(ud.getUsername()).setIssuedAt(new Date())
  7.             .setExpiration(new Date(System.currentTimeMillis() + expiration))
  8.             .signWith(SignatureAlgorithm.HS256, secret).compact();
  9.     }
  10. }
复制代码
1.2.5 后续请求认证(插件层:Filter)

自定义过滤器代码
  1. @Component
  2. @RequiredArgsConstructor
  3. public class JwtAuthFilter extends OncePerRequestFilter {
  4.     private final JwtUtils jwtUtils;
  5.     private final UserDetailsServiceImpl userDetailsService;
  6.     @Override protected void doFilterInternal(HttpServletRequest req, HttpServletResponse res, FilterChain chain) {
  7.         String token = parseJwt(req);
  8.         if (token != null && jwtUtils.validateToken(token)) {
  9.             String username = jwtUtils.extractUsername(token);
  10.             UserDetails ud = userDetailsService.loadUserByUsername(username);
  11.             UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(ud, null, ud.getAuthorities());
  12.             SecurityContextHolder.getContext().setAuthentication(auth);
  13.         }
  14.         chain.doFilter(req, res);
  15.     }
  16.     private String parseJwt(HttpServletRequest req) {
  17.         String h = req.getHeader("Authorization");
  18.         return (h != null && h.startsWith("Bearer ")) ? h.substring(7) : null;
  19.     }
  20. }
复制代码
1.3 login接口执行流程图

graph TD    A[前端发起登录请求\nPOST /api/auth/login] --> B[AuthController.login]    B --> C[AuthenticationManager.authenticate]    C --> D[DaoAuthenticationProvider.authenticate]    D --> E[UserDetailsServiceImpl.loadUserByUsername]    E --> F[UserMapper.selectOne\n查询用户基础信息]    E --> G[RoleMapper.findRolesByUserId\n加载角色权限]    D --> H[additionalAuthenticationChecks\n密码校验]    H --> I[BCryptPasswordEncoder.matches\n比对密码]    D --> J[生成已认证凭证\nUsernamePasswordAuthenticationToken]    J --> K[JwtUtils.generateToken\n生成JWT Token]    K --> L[返回Token给前端]二、@PreAuthorize接口鉴权流程

2.1 流程概述

@PreAuthorize是方法级权限控制注解,核心是在方法执行前校验用户权限。流程涉及AOP拦截权限解析授权决策三个阶段。
2.2 详细步骤与代码示例

2.2.1 控制器接口标注@PreAuthorize(表现层)
  1. @RestController
  2. @RequestMapping("/api/order")
  3. @RequiredArgsConstructor
  4. public class OrderController {
  5.     private final OrderService orderService;
  6.     @GetMapping
  7.     @PreAuthorize("hasAuthority('order:view')")
  8.     public PageResult<OrderVo> listOrders(OrderQuery query) {
  9.         return orderService.queryOrders(query);
  10.     }
  11. }
复制代码
2.2.2 AOP拦截与权限表达式解析(插件层)

配置类代码
  1. @Configuration
  2. @EnableGlobalMethodSecurity(prePostEnabled = true)
  3. public class MethodSecurityConfig extends GlobalMethodSecurityConfiguration {
  4.     @Override protected MethodSecurityExpressionHandler createExpressionHandler() {
  5.         DefaultMethodSecurityExpressionHandler h = new DefaultMethodSecurityExpressionHandler();
  6.         h.setPermissionEvaluator(new CustomPermissionEvaluator());
  7.         return h;
  8.     }
  9. }
复制代码
MethodSecurityInterceptor源码核心逻辑
  1. public class MethodSecurityInterceptor implements MethodInterceptor {
  2.     public Object invoke(MethodInvocation mi) {
  3.         Collection<ConfigAttribute> attrs = attributeSource.getAttributes(mi);
  4.         if (attrs == null) return mi.proceed();
  5.         Authentication auth = SecurityContextHolder.getContext().getAuthentication();
  6.         accessDecisionManager.decide(auth, mi, attrs);
  7.         return mi.proceed();
  8.     }
  9. }
复制代码
2.2.3 权限校验逻辑(Service层)

自定义权限检查器
  1. @Component
  2. public class PermissionChecker {
  3.     public boolean hasPermission(String code) {
  4.         Authentication auth = SecurityContextHolder.getContext().getAuthentication();
  5.         return auth.getAuthorities().stream().anyMatch(a -> a.getAuthority().equals(code));
  6.     }
  7. }
复制代码
表达式解析源码核心逻辑(SecurityExpressionRoot):
  1. public class SecurityExpressionRoot {
  2.     public boolean hasAuthority(String auth) {
  3.         return authentication.getAuthorities().stream().anyMatch(a -> a.getAuthority().equals(auth));
  4.     }
  5. }
复制代码
授权决策管理器源码核心逻辑(AffirmativeBased):
  1. public class AffirmativeBased implements AccessDecisionManager {
  2.     public void decide(Authentication auth, Object obj, Collection<ConfigAttribute> attrs) {
  3.         for (AccessDecisionVoter v : decisionVoters) {
  4.             int r = v.vote(auth, obj, attrs);
  5.             if (r == ACCESS_GRANTED) return;
  6.         }
  7.         throw new AccessDeniedException("权限不足");
  8.     }
  9. }
复制代码
2.2.4 业务逻辑执行(Service层)
  1. @Service
  2. @RequiredArgsConstructor
  3. public class OrderServiceImpl implements OrderService {
  4.     private final OrderMapper orderMapper;
  5.     private final DataScopeService dataScopeService;
  6.     public PageResult<OrderVo> queryOrders(OrderQuery q) {
  7.         DataScopeService.DataScope scope = dataScopeService.getCurUserDataScope();
  8.         LambdaQueryWrapper<OrderPo> w = new LambdaQueryWrapper<>();
  9.         if (scope.getScopeType() == 1) w.eq(OrderPo::getCreatorId, scope.getUserId());
  10.         else if (scope.getScopeType() == 2) w.eq(OrderPo::getDeptId, scope.getDeptIds().get(0));
  11.         Page<OrderPo> p = orderMapper.selectPage(new Page<>(q.getPageNum(), q.getPageSize()), w);
  12.         return convertToPageResult(p);
  13.     }
  14. }
复制代码
2.3 @PreAuthorize接口执行流程图

graph TD    A[前端携带Token请求GET /api/order] --> B[JwtAuthFilter.doFilterInternal]    B --> C[提取Token并验证]    C --> D[设置SecurityContextUsernamePasswordAuthenticationToken]    D --> E[DispatcherServlet分发请求]    E --> F[OrderController.listOrders@PreAuthorize标注方法]    F --> G[MethodSecurityInterceptor.invokeAOP拦截]    G --> H[attributeSource.getAttributes获取权限表达式]    H --> I[accessDecisionManager.decide授权决策]    I --> J[WebExpressionVoter.vote表达式投票]    J --> K[SecurityExpressionRoot.hasAuthority解析权限逻辑]    K --> L[PermissionChecker.hasPermission校验权限]    L --> M[OrderServiceImpl.queryOrders执行业务逻辑]    M --> N[返回数据给前端]三、Spring Security过滤器链详解

3.1 过滤器执行顺序与功能

顺序过滤器名称功能描述使用场景1SecurityContextPersistenceFilter恢复或清理SecurityContext,隔离请求间状态。所有请求必经,前后端分离可简化。2LogoutFilter处理退出请求,清理认证信息。需显式退出功能时启用。3UsernamePasswordAuthenticationFilter处理传统用户名密码登录请求。前后端分离通常替换为自定义登录接口。4JwtAuthFilter自定义过滤器,提取Bearer Token并设置认证信息。前后端分离核心过滤器,手动配置。5AnonymousAuthenticationFilter为未认证用户分配匿名身份。区分未登录与已登录用户。6ExceptionTranslationFilter捕获安全异常并转换为HTTP响应(401/403)。所有异常处理中枢,必配置。7FilterSecurityInterceptorURL级权限校验,根据authorizeRequests配置判断访问权限。粗粒度权限控制。3.2 过滤器链配置与自定义


  • 配置位置:SecurityConfig中通过HttpSecurity链式调用配置。
  • 自定义过滤器插入:使用addFilterBefore/After/At方法,如JwtAuthFilter插入到UsernamePasswordAuthenticationFilter之前。
四、核心流程总结

4.1 login接口核心流程
  1. 前端请求→AuthController.login()→AuthenticationManager.authenticate()→
  2. DaoAuthenticationProvider.authenticate()→UserDetailsServiceImpl.loadUserByUsername()→
  3. UserMapper.selectOne()→additionalAuthenticationChecks()→BCryptPasswordEncoder.matches()→
  4. 生成UsernamePasswordAuthenticationToken→JwtUtils.generateToken()→返回Token
复制代码
4.2 @PreAuthorize接口核心流程
  1. 前端携带Token请求→JwtAuthFilter.doFilterInternal()→设置SecurityContext→
  2. OrderController.listOrders()→MethodSecurityInterceptor.invoke()→
  3. attributeSource.getAttributes()→accessDecisionManager.decide()→
  4. WebExpressionVoter.vote()→SecurityExpressionRoot.hasAuthority()→
  5. PermissionChecker.hasPermission()→OrderServiceImpl.queryOrders()→返回数据
复制代码
通过上述流程图与源码剖析,可清晰理解Spring Security在认证与授权中的底层逻辑,以及自定义组件与源码组件的协作方式。

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

相关推荐

您需要登录后才可以回帖 登录 | 立即注册