Spring Security登录后仍返回403错误的问题求助
解决方案
你的问题核心是手动将用户存入HttpSession的方式不被Spring Security识别,Spring Security的权限校验依赖SecurityContextHolder中的Authentication对象,而非你直接存入Session的用户对象。以下是具体解决步骤:
1. 用Spring Security的AuthenticationManager完成认证
放弃手动验证凭据,改用Spring Security提供的AuthenticationManager处理认证逻辑,它会自动完成凭据校验,并生成合法的Authentication对象。
关键代码(LoginController)
@Controller public class LoginController { // 注入AuthenticationManager,需在SecurityConfig中暴露该Bean @Autowired private AuthenticationManager authenticationManager; @PostMapping("/login") public String login(@RequestParam String username, @RequestParam String password, HttpServletRequest request) { try { // 封装用户名密码为认证请求Token UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password); // 调用AuthenticationManager执行认证(会自动调用UserDetailsService校验用户) Authentication authentication = authenticationManager.authenticate(authRequest); // 将认证结果存入SecurityContext SecurityContext securityContext = SecurityContextHolder.createEmptyContext(); securityContext.setAuthentication(authentication); SecurityContextHolder.setContext(securityContext); // 将SecurityContext绑定到HttpSession,确保重定向后状态保留 request.getSession().setAttribute( HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY, securityContext ); return "redirect:/search"; } catch (AuthenticationException e) { // 认证失败,返回登录页并携带错误标记 return "redirect:/login?error"; } } }
2. 调整SecurityConfig配置
确保正确配置用户认证逻辑,并暴露AuthenticationManager供Controller使用,同时关闭Spring Security默认的登录表单(因为你用自定义登录页)。
关键代码(SecurityConfig)
@Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { // 自定义UserDetailsService,用于从数据库/缓存获取用户信息 @Autowired private UserDetailsService customUserDetailsService; // 配置密码编码器,必须和用户注册时的加密方式一致 @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } // 暴露AuthenticationManager Bean,让Controller可以注入 @Bean @Override public AuthenticationManager authenticationManagerBean() throws Exception { return super.authenticationManagerBean(); } @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { // 配置用户认证逻辑:用自定义UserDetailsService+密码编码器 auth.userDetailsService(customUserDetailsService) .passwordEncoder(passwordEncoder()); } @Override protected void configure(HttpSecurity http) throws Exception { http .csrf().disable() // 开发阶段可关闭,生产环境按需开启并配置 .authorizeRequests() // 允许未认证用户访问的路径 .antMatchers("/login", "/register", "/static/**").permitAll() // 其余所有路径需认证 .anyRequest().authenticated() .and() // 配置会话管理,默认即可保证SecurityContext持久化到Session .sessionManagement() .sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED); } }
3. 注意事项
- 必须给用户分配权限:UserDetailsService返回的UserDetails对象必须包含至少一个权限(比如
ROLE_USER),否则即使认证成功,访问受保护路径仍会触发403。 - 不要手动操作Session存储用户:所有登录状态必须通过
SecurityContext和Authentication对象管理,Spring Security的过滤器链只会识别这个上下文。 - 重定向后的上下文加载:Spring Security的
SecurityContextPersistenceFilter会自动从Session中读取SPRING_SECURITY_CONTEXT_KEY对应的SecurityContext,因此只要正确存入,重定向后SecurityContextHolder就会持有认证后的用户信息。
内容的提问来源于stack exchange,提问作者Nick
相关产品推荐
相关产品推荐

