手动认证关键代码逐行解析

手动认证关键代码逐行解析

手动认证关键代码逐行解析


UsernamePasswordAuthenticationToken authToken =

        new UsernamePasswordAuthenticationToken(

            userDetails,                    // ① principal

            null,                           // ② credentials

            userDetails.getAuthorities());  // ③ authorities



authToken.setDetails(

    new WebAuthenticationDetailsSource().buildDetails(request));



SecurityContextHolder.getContext().setAuthentication(authToken);

1️⃣ UsernamePasswordAuthenticationToken 构造器

| 参数 | 含义 | 常见取值 |

| --------------- | --------------------- | ------------------------------ |

| principal | 认证主体(谁) | 自定义 UserDetails 实例 |

| credentials | 登录凭证(密码/令牌) | 手动认证时通常设为 null |

| authorities | 权限集合 | userDetails.getAuthorities() |


2️⃣ setDetails(...):补充请求级元数据

  • WebAuthenticationDetailsSource.buildDetails(request) 生成

  • 默认包含:

    • remoteAddress(客户端 IP)

    • sessionId(当前会话 ID)

  • 可用于审计、IP 白名单、自定义 AccessDecisionVoter


3️⃣ SecurityContextHolder.getContext().setAuthentication(...)

  • 将认证令牌放入 当前线程SecurityContext

  • 默认实现:ThreadLocalSecurityContextHolderStrategy

  • 请求结束后由 SecurityContextPersistenceFilter 保存到 HttpSession,实现“登录状态保持”


典型使用场景

| 场景 | 触发点 |

| ------------ | --------------------------------------- |

| JWT 登录 | 自定义过滤器解析完 JWT 后手动建立上下文 |

| SSO / OAuth2 | 外部系统已认证,本地仅做上下文同步 |

| 单元测试 | 快速模拟已登录用户 |


注意事项清单

  • 线程安全:异步任务需手动传递或清空 SecurityContext

  • 密码擦除:手动认证时把 credentials 设为 null

  • Session 固定攻击:登录后调用 changeSessionId()

  • 并发会话控制:手动登录后需同步 SessionRegistry

一句话总结:告诉 Spring Security —— “此请求已认证,用户是 XXX,权限是 [ROLE_A, ROLE_B],请放行”。





本文由萧兮的博客原创发布,欢迎转载,转载务必保留原文链接。

萧兮的博客https://www.20010515.xyz · 原文:https://www.20010515.xyz/posts/87bdaa2e-5595-4adb-9040-79d72f09090d