如何实现OAuth2+JWT无状态认证中的JWT提取与响应头设置
实现OAuth2授权后提取JWT并设置到响应头的方案
刚好我之前做过类似的无状态OAuth2+JWT认证方案,你要实现的这个高亮步骤,核心就是重写Spring Security的OAuth2登录成功处理器,在授权回调完成后提取JWT并塞进响应头,下面是具体的实现步骤,一步步来就行:
1. 自定义OAuth2登录成功处理器
Spring Security在OAuth2授权兑换token成功后,会触发登录成功的事件,默认处理器只会做重定向操作。我们需要自定义一个处理器,插入提取JWT并设置响应头的逻辑。
创建一个继承SavedRequestAwareAuthenticationSuccessHandler的自定义处理器:
import org.springframework.security.core.Authentication; import org.springframework.security.oauth2.provider.OAuth2Authentication; import org.springframework.security.oauth2.provider.authentication.OAuth2AuthenticationDetails; import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; public class CustomOAuth2SuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler { @Override public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws ServletException, IOException { // 从认证上下文里提取OAuth2相关的认证信息 if (authentication instanceof OAuth2Authentication) { OAuth2Authentication oAuth2Auth = (OAuth2Authentication) authentication; OAuth2AuthenticationDetails authDetails = (OAuth2AuthenticationDetails) oAuth2Auth.getDetails(); // 提取授权服务器返回的JWT Token String jwtToken = authDetails.getTokenValue(); // 将JWT写入响应头,这里自定义头名称,比如X-JWT-Token,方便前端识别 response.setHeader("X-JWT-Token", jwtToken); } // 继续执行默认的重定向逻辑,回到用户最初请求的受保护资源(比如/) super.onAuthenticationSuccess(request, response, authentication); } }
2. 配置Spring Security,替换默认处理器
接下来要把自定义的处理器绑定到Spring Security的OAuth2登录流程中,根据你的Spring Boot版本,有两种配置方式:
方式一:Spring Boot < 2.7(基于WebSecurityConfigurerAdapter)
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.config.http.SessionCreationPolicy; @Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Bean public CustomOAuth2SuccessHandler customOAuth2SuccessHandler() { return new CustomOAuth2SuccessHandler(); } @Override protected void configure(HttpSecurity http) throws Exception { http .authorizeRequests() .anyRequest().authenticated() .and() .oauth2Login() .successHandler(customOAuth2SuccessHandler()) // 绑定自定义成功处理器 .and() .sessionManagement() .sessionCreationPolicy(SessionCreationPolicy.STATELESS); // 开启无状态模式,符合你的需求 } }
方式二:Spring Boot >= 2.7(基于SecurityFilterChain)
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.http.SessionCreationPolicy; import org.springframework.security.web.SecurityFilterChain; @Configuration public class SecurityConfig { @Bean public CustomOAuth2SuccessHandler customOAuth2SuccessHandler() { return new CustomOAuth2SuccessHandler(); } @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http .authorizeHttpRequests(auth -> auth .anyRequest().authenticated() ) .oauth2Login(oauth2 -> oauth2 .successHandler(customOAuth2SuccessHandler()) // 绑定自定义成功处理器 ) .sessionManagement(session -> session .sessionCreationPolicy(SessionCreationPolicy.STATELESS) // 开启无状态会话 ); return http.build(); } }
3. 逻辑验证说明
- 当授权服务器回调到
/login?code=xxx&state=yyy时,Spring Security会自动完成code兑换access_token的流程,把OAuth2Authentication对象存入安全上下文。 - 自定义处理器会拦截登录成功事件,从
OAuth2AuthenticationDetails中提取JWT(也就是授权服务器返回的access_token,要确保授权服务器返回的是JWT格式)。 - 处理器把JWT写入响应头后,会继续执行默认的重定向逻辑,回到用户最初请求的
/路径。 - 前端AngularJS加载
/时,通过响应拦截器读取这个自定义响应头,将JWT存入localStorage,后续请求就可以通过httpInterceptor注入Authorization: Bearer <token>头完成认证。
额外注意事项
- 确认你的OAuth2授权服务器返回的access_token是JWT格式,否则
getTokenValue()拿到的内容无法被前端解析使用。 - 响应头名称可以根据业务需求自定义,只要前端和后端保持一致即可。
- 一定要配置
SessionCreationPolicy.STATELESS,确保服务器端不创建会话,符合无状态认证的要求。
内容的提问来源于stack exchange,提问作者Hari
相关产品推荐
相关产品推荐

