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

如何配置Spring Security OAuth2授权服务器仅向指定角色颁发令牌

解决方案:限制仅指定角色用户获取OAuth2令牌

问题原因

你之前的配置错误地给所有授权服务器端点添加了用户角色校验,但令牌交换端点(/oauth2/token)是基于客户端认证(Client ID/Secret)的,不需要用户身份,因此客户端请求该端点时会因缺少用户角色权限返回401。

正确的拦截时机应该是在用户授权阶段(即用户登录后访问/oauth2/authorize端点确认授权时),此时用户身份已存在,校验角色即可阻止无权限用户完成授权流程。

修正后的代码

保留默认的授权服务器安全配置,仅针对授权端点添加角色校验:

@Bean
@Order(1)
public SecurityFilterChain authServerSecurityFilterChain(HttpSecurity http) throws Exception {
    // 保留默认安全配置,正确处理各端点的认证方式
    OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(http);

    // 仅对用户授权端点校验角色,ADMIN/USER可进入授权页面
    http.authorizeHttpRequests(authorize -> authorize
            .requestMatchers("/oauth2/authorize").hasAnyRole("USER", "ADMIN")
            .anyRequest().permitAll()
    );

    http.getConfigurer(OAuth2AuthorizationServerConfigurer.class)
            .oidc(Customizer.withDefaults());

    http.exceptionHandling(
            e -> e.authenticationEntryPoint(
                    new LoginUrlAuthenticationEntryPoint("/login")
            )
    );
    return http.build();
}

同时确保用户登录的安全过滤器链正确配置(用于加载用户角色):

@Bean
@Order(2)
public SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {
    http.authorizeHttpRequests(authorize -> authorize
            .anyRequest().authenticated()
    )
    .formLogin(form -> form
            .loginPage("/login")
            .permitAll()
    );
    return http.build();
}

进阶:更细粒度的角色校验

如果需要在生成授权码前就拦截无权限请求,可以自定义认证提供者:

@Component
public class CustomOAuth2AuthorizationRequestAuthenticationProvider extends OAuth2AuthorizationRequestAuthenticationProvider {

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        OAuth2AuthorizationRequestAuthenticationToken authRequest = 
            (OAuth2AuthorizationRequestAuthenticationToken) authentication;
        
        // 获取当前登录用户的身份信息
        Authentication userAuth = SecurityContextHolder.getContext().getAuthentication();
        boolean hasValidRole = userAuth.getAuthorities().stream()
                .anyMatch(auth -> auth.getAuthority().equals("ROLE_USER") || auth.getAuthority().equals("ROLE_ADMIN"));
        
        if (!hasValidRole) {
            throw new AccessDeniedException("无权限发起授权请求");
        }
        
        return super.authenticate(authentication);
    }
}

然后将该提供者注册到授权服务器配置中:

http.getConfigurer(OAuth2AuthorizationServerConfigurer.class)
        .authorizationRequest(authRequestConfig -> authRequestConfig
                .authenticationProvider(new CustomOAuth2AuthorizationRequestAuthenticationProvider())
        )
        .oidc(Customizer.withDefaults());

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 15:28:19