Spring Security集成JWT后无法认证登录问题求助
1. 自定义AuthenticationProvider未注册到Security链
你的CustomAuthenticationProvider虽标注了@Service,但未被加入Spring Security的认证体系,默认会使用内置的DaoAuthenticationProvider,导致自定义认证逻辑根本没执行。
修复方法:在SecurityConfig中注入并配置自定义认证提供者:
@Configuration public class SecurityConfig { @Autowired private CustomAuthenticationProvider customAuthenticationProvider; @Bean SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception { // ... 原有配置 ... http.authenticationProvider(customAuthenticationProvider); // 添加这行注册自定义Provider // ... 原有配置 ... } // ... 其他Bean定义 ... }
2. 无状态会话与表单登录的冲突
你配置了session.sessionCreationPolicy(SessionCreationPolicy.STATELESS),但Spring Security默认表单登录依赖会话保存认证状态。无状态模式下不会创建会话,登录成功后无法维持认证状态,导致后续请求直接跳回登录页。
修复方案二选一:
- 保留表单登录:修改会话策略为
IF_REQUIREDhttp.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)) - 坚持无状态:弃用默认表单登录,改用API接口(如
POST /login)登录,登录成功后返回JWT,前端后续请求携带JWT请求头。
3. JWT生成时机错误
JWTTokenGeneratorFilter的shouldNotFilter方法限定只有请求/user时才生成Token,但默认表单登录成功后不会自动请求/user,导致登录后无法获取JWT,后续请求无认证凭证,被拦截跳回登录页。
修复方法:调整过滤器触发条件,或添加登录成功处理器直接生成Token:
方式一:修改过滤器触发逻辑
@Override protected boolean shouldNotFilter(HttpServletRequest request) { // 让登录请求和/user请求都触发Token生成 return !request.getServletPath().equals("/login") && !request.getServletPath().equals("/user"); }
方式二:添加登录成功处理器(更推荐)
// 在SecurityConfig的formLogin配置中添加 .formLogin(form -> form .successHandler((request, response, authentication) -> { // 复制JWTTokenGeneratorFilter中的Token生成逻辑 SecretKey key = Keys.hmacShaKeyFor(SecurityConstants.JWT_KEY.getBytes(StandardCharsets.UTF_8)); String jwt = Jwts.builder().setIssuer("Eazy Bank").setSubject("JWT Token") .claim("username", authentication.getName()) .claim("authorities", populateAuthorities(authentication.getAuthorities())) .setIssuedAt(new Date()) .setExpiration(new Date((new Date()).getTime() + 30000000)) .signWith(key).compact(); response.setHeader(SecurityConstants.JWT_HEADER, jwt); // 返回JSON格式的Token response.setContentType("application/json"); response.getWriter().write("{\"token\":\"" + jwt + "\"}"); }) )
注:需将populateAuthorities方法提取为公共方法,方便复用
4. 角色权限匹配问题
/customerList配置了.hasRole("USER"),但CustomAuthenticationProvider返回的是SimpleGrantedAuthority(auth.getName())。Spring Security的hasRole会自动给权限添加ROLE_前缀,即只有权限为ROLE_USER时才能访问该接口;若数据库中存储的权限是USER,会导致权限不匹配,被拦截跳回登录页。
修复方案二选一:
- 修改数据库中的权限为
ROLE_USER,保持hasRole配置不变; - 将
hasRole("USER")改为hasAuthority("USER"),直接匹配原始权限名:.requestMatchers("/customerList").hasAuthority("USER")
内容的提问来源于stack exchange,提问作者Tara

