Spring Boot控制器中如何在登录响应时向客户端发送Bearer JWT授权头?
在Spring Security+JWT应用中把Bearer令牌放入登录响应头
要实现登录成功后将Bearer格式的JWT令牌写入响应头,主要有两种方案,根据你的登录实现方式选择:
方案一:自定义登录接口(推荐,灵活可控)
如果是自己编写登录接口,验证用户身份后生成JWT,直接往响应头添加即可:
1. 编写登录Controller
@RestController @RequestMapping("/auth") public class AuthController { private final JwtTokenProvider jwtTokenProvider; private final UserDetailsService userDetailsService; private final PasswordEncoder passwordEncoder; public AuthController(JwtTokenProvider jwtTokenProvider, UserDetailsService userDetailsService, PasswordEncoder passwordEncoder) { this.jwtTokenProvider = jwtTokenProvider; this.userDetailsService = userDetailsService; this.passwordEncoder = passwordEncoder; } @PostMapping("/login") public ResponseEntity<Void> login(@RequestBody LoginRequest loginRequest) { // 验证用户名和密码 UserDetails userDetails = userDetailsService.loadUserByUsername(loginRequest.getUsername()); if (!passwordEncoder.matches(loginRequest.getPassword(), userDetails.getPassword())) { throw new BadCredentialsException("用户名或密码错误"); } // 生成JWT令牌 String token = jwtTokenProvider.generateToken(userDetails); // 构建响应头,添加Bearer令牌 HttpHeaders headers = new HttpHeaders(); headers.add(HttpHeaders.AUTHORIZATION, "Bearer " + token); // 返回响应,无响应体(也可根据需求返回用户信息) return ResponseEntity.ok().headers(headers).build(); } } // 登录请求DTO record LoginRequest(String username, String password) {}
2. JWT生成工具类
@Component public class JwtTokenProvider { @Value("${jwt.secret}") private String secretKey; @Value("${jwt.expiration-ms}") private long expirationMs; public String generateToken(UserDetails userDetails) { // 设置JWT声明信息 Claims claims = Jwts.claims().setSubject(userDetails.getUsername()); claims.put("roles", userDetails.getAuthorities().stream() .map(GrantedAuthority::getAuthority) .toList()); Date now = new Date(); Date expiryDate = new Date(now.getTime() + expirationMs); // 生成并返回JWT return Jwts.builder() .setClaims(claims) .setIssuedAt(now) .setExpiration(expiryDate) .signWith(SignatureAlgorithm.HS256, secretKey) .compact(); } }
方案二:自定义Spring Security登录成功处理器(适配默认表单登录)
如果使用Spring Security默认的表单登录流程,需要自定义AuthenticationSuccessHandler来改写响应头:
1. 自定义成功处理器
@Component public class JwtLoginSuccessHandler implements AuthenticationSuccessHandler { private final JwtTokenProvider jwtTokenProvider; private final ObjectMapper objectMapper; public JwtLoginSuccessHandler(JwtTokenProvider jwtTokenProvider, ObjectMapper objectMapper) { this.jwtTokenProvider = jwtTokenProvider; this.objectMapper = objectMapper; } @Override public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException { // 获取登录用户信息 UserDetails userDetails = (UserDetails) authentication.getPrincipal(); // 生成JWT String token = jwtTokenProvider.generateToken(userDetails); // 添加Bearer令牌到响应头 response.addHeader(HttpHeaders.AUTHORIZATION, "Bearer " + token); // 设置响应类型并返回登录成功信息 response.setContentType(MediaType.APPLICATION_JSON_VALUE); response.setCharacterEncoding(StandardCharsets.UTF_8.name()); objectMapper.writeValue(response.getWriter(), Map.of("message", "登录成功")); } }
2. 配置Spring Security
@Configuration @EnableWebSecurity public class SecurityConfig { private final JwtLoginSuccessHandler loginSuccessHandler; private final UserDetailsService userDetailsService; private final PasswordEncoder passwordEncoder; public SecurityConfig(JwtLoginSuccessHandler loginSuccessHandler, UserDetailsService userDetailsService, PasswordEncoder passwordEncoder) { this.loginSuccessHandler = loginSuccessHandler; this.userDetailsService = userDetailsService; this.passwordEncoder = passwordEncoder; } @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http .csrf(csrf -> csrf.disable()) .authorizeHttpRequests(auth -> auth .requestMatchers("/auth/login").permitAll() .anyRequest().authenticated() ) .formLogin(form -> form .loginProcessingUrl("/auth/login") // 表单提交的URL .successHandler(loginSuccessHandler) // 绑定自定义成功处理器 ); return http.build(); } @Bean public AuthenticationManager authenticationManager(AuthenticationConfiguration authConfig) throws Exception { return authConfig.getAuthenticationManager(); } @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } }
关键配置与注意事项
- 在
application.properties中配置JWT参数:jwt.secret=your-strong-secret-key-keep-it-safe jwt.expiration-ms=86400000 # 24小时有效期 - 客户端需要从响应头的
Authorization字段提取令牌,后续请求时将该令牌放入请求头的Authorization字段(格式同样为Bearer {token})。 - 生产环境中,JWT密钥要使用高复杂度的随机字符串,避免硬编码,建议通过环境变量注入。
内容的提问来源于stack exchange,提问作者Kreuterkeule
相关产品推荐
相关产品推荐

