Spring Security问题:手动添加UsernamePasswordAuthenticationFilter后登录触发重定向
Spring Security 登录后重定向导致403问题解决
我正在学习Spring Security,计划开发独立前端与Spring Web后端交互。目前在用户名/密码登录时遇到问题:凭证验证通过,但返回403 Forbidden错误,推测与登录后的重定向行为有关。
当前配置
SecurityFilterChain 基础配置
http.csrf().disable() .formLogin().disable() .authorizeRequests() .antMatchers("/login", "/error").permitAll() .anyRequest().authenticated();
自定义用户名密码过滤器
由于禁用默认表单登录后,UsernamePasswordAuthenticationFilter不存在,因此手动添加了自定义验证逻辑的过滤器:
UsernamePasswordAuthenticationFilter filter = new UsernamePasswordAuthenticationFilter(authentication -> { String username = authentication.getPrincipal().toString(); String password = authentication.getCredentials().toString(); if (username.isEmpty() || password.isEmpty()) { throw new BadCredentialsException("Username or password not specified"); } if (!username.equals("u") || !password.equals("p")) { throw new BadCredentialsException("Wrong username or password"); } return new UsernamePasswordAuthenticationToken(username, null); }); http.addFilter(filter);
调试日志
[nio-8079-exec-3] o.s.security.web.FilterChainProxy : Securing POST /login?username=u&password=p [nio-8079-exec-3] s.s.w.c.SecurityContextPersistenceFilter : Set SecurityContextHolder to empty SecurityContext [nio-8079-exec-3] w.a.UsernamePasswordAuthenticationFilter : Set SecurityContextHolder to UsernamePasswordAuthenticationToken [Principal=u, Credentials=[PROTECTED], Authenticated=false, Details=null, Granted Authorities=[]] [nio-8079-exec-3] o.s.s.web.DefaultRedirectStrategy : Redirecting to http://localhost:8079/ [nio-8079-exec-3] w.c.HttpSessionSecurityContextRepository : Stored SecurityContextImpl [Authentication=UsernamePasswordAuthenticationToken [Principal=u, Credentials=[PROTECTED], Authenticated=false, Details=null, Granted Authorities=[]]] to HttpSession [org.springframework.session.web.http.SessionRepositoryFilter$SessionRepositoryRequestWrapper$HttpSessionWrapper@7ba6bfb2] [nio-8079-exec-3] w.c.HttpSessionSecurityContextRepository : Stored SecurityContextImpl [Authentication=UsernamePasswordAuthenticationToken [Principal=u, Credentials=[PROTECTED], Authenticated=false, Details=null, Granted Authorities=[]]] to HttpSession [org.springframework.session.web.http.SessionRepositoryFilter$SessionRepositoryRequestWrapper$HttpSessionWrapper@7ba6bfb2] [nio-8079-exec-3] s.s.w.c.SecurityContextPersistenceFilter : Cleared SecurityContextHolder to complete request [nio-8079-exec-4] o.s.security.web.FilterChainProxy : Securing POST / [nio-8079-exec-4] w.c.HttpSessionSecurityContextRepository : Retrieved SecurityContextImpl [Authentication=UsernamePasswordAuthenticationToken [Principal=u, Credentials=[PROTECTED], Authenticated=false, Details=null, Granted Authorities=[]]] [nio-8079-exec-4] s.s.w.c.SecurityContextPersistenceFilter : Set SecurityContextHolder to SecurityContextImpl [Authentication=UsernamePasswordAuthenticationToken [Principal=u, Credentials=[PROTECTED], Authenticated=false, Details=null, Granted Authorities=[]]] [nio-8079-exec-4] o.s.s.w.s.HttpSessionRequestCache : Loaded matching saved request http://localhost:8079/ [nio-8079-exec-4] o.s.s.a.dao.DaoAuthenticationProvider : Failed to authenticate since no credentials provided [nio-8079-exec-4] o.s.s.w.s.HttpSessionRequestCache : Saved request http://localhost:8079/ to session [nio-8079-exec-4] o.s.s.w.a.Http403ForbiddenEntryPoint : Pre-authenticated entry point called. Rejecting access [nio-8079-exec-4] w.c.HttpSessionSecurityContextRepository : Did not store empty SecurityContext [nio-8079-exec-4] w.c.HttpSessionSecurityContextRepository : Did not store empty SecurityContext [nio-8079-exec-4] s.s.w.c.SecurityContextPersistenceFilter : Cleared SecurityContextHolder to complete request [nio-8079-exec-4] o.s.security.web.FilterChainProxy : Securing POST /error [nio-8079-exec-4] s.s.w.c.SecurityContextPersistenceFilter : Set SecurityContextHolder to empty SecurityContext [nio-8079-exec-4] o.s.s.w.a.AnonymousAuthenticationFilter : Set SecurityContextHolder to anonymous SecurityContext [nio-8079-exec-4] o.s.security.web.FilterChainProxy : Secured POST /error [nio-8079-exec-4] w.c.HttpSessionSecurityContextRepository : Did not store anonymous SecurityContext [nio-8079-exec-4] w.c.HttpSessionSecurityContextRepository : Did not store anonymous SecurityContext [nio-8079-exec-4] s.s.w.c.SecurityContextPersistenceFilter : Cleared SecurityContextHolder to complete request
问题分析与解决
从日志能定位两个关键问题:
- 生成的
UsernamePasswordAuthenticationToken未标记为已认证(Authenticated=false),且无任何权限,导致重定向到根路径/时被拦截返回403。 - 默认的
UsernamePasswordAuthenticationFilter在认证成功后会执行重定向,这和前后端分离场景的需求冲突。
按以下步骤修复:
1. 正确生成已认证的AuthenticationToken
Spring Security中,只有带GrantedAuthority参数的UsernamePasswordAuthenticationToken构造器会自动将token标记为已认证。修改token生成逻辑:
List<GrantedAuthority> authorities = Collections.singletonList(new SimpleGrantedAuthority("ROLE_USER")); return new UsernamePasswordAuthenticationToken(username, null, authorities);
2. 自定义认证成功处理器,取消重定向
创建一个AuthenticationSuccessHandler,直接返回JSON响应而非重定向:
AuthenticationSuccessHandler successHandler = (request, response, authentication) -> { response.setContentType("application/json;charset=UTF-8"); response.setStatus(HttpServletResponse.SC_OK); response.getWriter().write("{\"code\":200,\"message\":\"登录成功\"}"); };
3. 给过滤器绑定自定义成功处理器
将成功处理器设置到过滤器中,确保认证成功后执行自定义逻辑:
// 原过滤器逻辑保留,添加以下配置 filter.setAuthenticationSuccessHandler(successHandler); // 若你的登录请求路径不是默认的/login,可手动设置: // filter.setFilterProcessesUrl("/api/login"); http.addFilter(filter);
4. 可选:禁用请求缓存
如果不需要Spring Security保存未认证前的请求,可禁用请求缓存彻底避免重定向触发:
http.requestCache().requestCache(new NullRequestCache());
调整完成后,登录成功会直接返回200状态码的JSON响应,不会触发重定向,同时token已正确标记为已认证,后续接口请求可正常通过权限校验。
内容的提问来源于stack exchange,提问作者Stefa168
相关产品推荐
相关产品推荐

