You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 19:08:07