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

Spring Boot 3.0 OAuth2资源服务器:@PreAuthorize实现用户角色API授权

Spring Boot 3.0 OAuth2资源服务器:基于user-authorities实现@PreAuthorize授权验证

核心实现步骤

1. 开启方法级安全支持

在Spring Boot启动类上添加@EnableMethodSecurity注解,启用方法级权限验证能力:

@SpringBootApplication
@EnableMethodSecurity
public class ResourceServerApplication {
    public static void main(String[] args) {
        SpringApplication.run(ResourceServerApplication.class, args);
    }
}

2. 自定义Opaque Token解析器

默认的Opaque Token解析器不会自动映射自定义的user-authorities字段为Spring Security权限,需自定义解析逻辑提取该字段并转换为GrantedAuthority:

import org.springframework.security.oauth2.core.OAuth2AuthenticatedPrincipal;
import org.springframework.security.oauth2.server.resource.introspection.NimbusOpaqueTokenIntrospector;
import org.springframework.security.oauth2.server.resource.introspection.OpaqueTokenIntrospector;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.oauth2.core.DefaultOAuth2AuthenticatedPrincipal;

import java.util.Collection;
import java.util.Map;

public class CustomOpaqueTokenIntrospector implements OpaqueTokenIntrospector {

    private final OpaqueTokenIntrospector delegate;

    public CustomOpaqueTokenIntrospector(String introspectionUri, String clientId, String clientSecret) {
        this.delegate = new NimbusOpaqueTokenIntrospector(introspectionUri, clientId, clientSecret);
    }

    @Override
    public OAuth2AuthenticatedPrincipal introspect(String token) {
        OAuth2AuthenticatedPrincipal principal = this.delegate.introspect(token);
        Map<String, Object> attributes = principal.getAttributes();
        
        // 提取token中的user-authorities字段
        Collection<String> userAuthorities = (Collection<String>) attributes.get("user-authorities");
        
        // 返回包含自定义权限的认证主体
        return new DefaultOAuth2AuthenticatedPrincipal(
                principal.getName(),
                attributes,
                userAuthorities.stream()
                        .map(SimpleGrantedAuthority::new)
                        .toList()
        );
    }
}

3. 配置资源服务器安全链

将自定义Token解析器配置到Spring Security资源服务器中:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.web.SecurityFilterChain;

@Configuration
public class ResourceServerConfig {

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
                .authorizeHttpRequests(auth -> auth
                        .anyRequest().authenticated()
                )
                .oauth2ResourceServer(oauth2 -> oauth2
                        .opaqueToken(token -> token
                                .introspector(new CustomOpaqueTokenIntrospector(
                                        "http://localhost:8080/oauth2/introspect", // 授权服务器Token introspect地址
                                        "client", // 资源服务器client ID
                                        "client-secret" // 资源服务器client secret
                                ))
                        )
                );
        return http.build();
    }
}

4. 使用@PreAuthorize验证权限

在Controller方法上添加@PreAuthorize注解,通过hasAuthority匹配user-authorities中的权限值:

import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class ApiController {

    @GetMapping("/read")
    @PreAuthorize("hasAuthority('READ_PRIVILEGE')")
    public String readResource() {
        return "读取资源成功";
    }

    @GetMapping("/write")
    @PreAuthorize("hasAuthority('WRITE_PRIVILEGE')")
    public String writeResource() {
        return "写入资源成功";
    }
}

关键注意事项

  • 若需使用hasRole注解,需在转换权限时添加ROLE_前缀,例如new SimpleGrantedAuthority("ROLE_" + authority),此时注解写法为@PreAuthorize("hasRole('READ_PRIVILEGE')")。
  • 确保授权服务器返回的Token中包含user-authorities字段,且格式为字符串数组。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 12:55:34