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

Spring Security OAuth2始终返回403问题排查求助

解决方案:Spring Boot OAuth2 配置——保护所有端点,放行特定接口

看起来你已经在搭建OAuth2授权服务器了,要实现「除认证、创建账户和部分信息类端点外,所有接口都需要安全保护」的需求,咱们可以通过授权服务器配置+全局HTTP安全配置两步来完成,下面是完整的实现方案:

1. 完善OAuth2授权服务器配置

首先补全你未写完的OAuth2Config,这里包含客户端信息、令牌存储、端点配置等核心内容:

@Configuration
@EnableAuthorizationServer
public class OAuth2Config extends AuthorizationServerConfigurerAdapter {

    @Autowired
    private AuthenticationManager authenticationManager;

    @Autowired
    private MongoTokenStore tokenStore;

    // 注入自定义用户详情服务,用于验证用户身份
    @Autowired
    private UserDetailsService userDetailsService;

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        // 这里配置你的OAuth2客户端信息,生产环境建议从数据库读取,示例用内存存储
        clients.inMemory()
                .withClient("your-app-client")
                .secret("{noop}your-client-secret") // 测试用明文,生产环境替换为BCrypt加密后的密文
                .authorizedGrantTypes("password", "refresh_token") // 支持密码模式和刷新令牌
                .scopes("read", "write") // 客户端权限范围
                .accessTokenValiditySeconds(3600) // 访问令牌有效期1小时
                .refreshTokenValiditySeconds(86400); // 刷新令牌有效期1天
    }

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints
                .tokenStore(tokenStore) // 用MongoDB存储令牌
                .authenticationManager(authenticationManager) // 绑定认证管理器,支持密码模式
                .userDetailsService(userDetailsService); // 刷新令牌时验证用户有效性
    }

    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
        // 允许公开访问令牌密钥端点,允许认证用户检查令牌,允许表单提交获取令牌
        security
                .tokenKeyAccess("permitAll()")
                .checkTokenAccess("isAuthenticated()")
                .allowFormAuthenticationForClients();
    }
}

2. 配置全局HTTP安全规则

这一步是实现「大部分端点保护,少数放行」的核心,根据你使用的Spring Security版本,分两种写法:

写法一:Spring Security 5.7及之前版本(使用WebSecurityConfigurerAdapter)

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private UserDetailsService userDetailsService;

    // 密码编码器,生产环境必须用BCrypt等安全加密方式
    @Bean
    public PasswordEncoder passwordEncoder() {
        // 测试用明文编码器,生产替换为 new BCryptPasswordEncoder()
        return NoOpPasswordEncoder.getInstance();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
    }

    // 暴露AuthenticationManager给OAuth2配置使用
    @Override
    @Bean
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .csrf().disable() // REST API通常关闭CSRF防护
                .authorizeRequests()
                // 放行不需要认证的端点:根据你的实际接口路径调整
                .antMatchers("/api/auth/**", "/api/users/register", "/api/public/**").permitAll()
                // 其他所有端点必须经过认证
                .anyRequest().authenticated()
                .and()
                .sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS); // REST API用无状态会话,不创建Session
    }
}

写法二:Spring Security 5.7+ 或 Spring Boot 2.7+(推荐,WebSecurityConfigurerAdapter已过时)

@Configuration
@EnableWebSecurity
public class WebSecurityConfig {

    @Autowired
    private UserDetailsService userDetailsService;

    @Bean
    public PasswordEncoder passwordEncoder() {
        // 生产环境推荐用BCryptPasswordEncoder
        return new BCryptPasswordEncoder();
    }

    // 暴露AuthenticationManager
    @Bean
    public AuthenticationManager authenticationManager(AuthenticationConfiguration authConfig) throws Exception {
        return authConfig.getAuthenticationManager();
    }

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
                .csrf(csrf -> csrf.disable())
                .authorizeHttpRequests(auth -> auth
                        // 放行的端点列表,按需调整
                        .requestMatchers("/api/auth/login", "/api/users/register", "/api/public/info").permitAll()
                        .anyRequest().authenticated()
                )
                .sessionManagement(session -> session
                        .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                );
        return http.build();
    }
}

关键注意点

  • 放行端点调整:你需要根据自己项目的实际接口路径,修改antMatchers或requestMatchers里的内容,确保注册、登录、公开信息类接口都被permitAll()放行。
  • 密码加密:生产环境绝对不能用NoOpPasswordEncoder,必须使用BCryptPasswordEncoder或更安全的加密方式,注册用户时要提前对密码进行加密。
  • 无状态会话:设置SessionCreationPolicy.STATELESS符合REST API的无状态设计,避免服务器存储会话信息。
  • Spring Boot 3.x 注意:@EnableAuthorizationServer在Spring Boot 3.x中已过时,官方推荐使用Spring Authorization Server替代,如果是新项目建议直接用新组件。

内容的提问来源于stack exchange,提问作者Monta

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 11:55:31