oauth2-resource-server授权配置介绍

本文介绍了如何在SpringBoot项目中配置OAuth2ResourceServer,包括使用官方配置、自定义JWK设置和JWT解析,以及处理不同权限认证方案的过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、背景

当了解这篇文章授权服务器后,对授权服务器有一定的认识,那么授权服务器生成token后,该怎么用呢,这就涉及到资源服务器,现在给大家简单介绍实现过程。

2、方案

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
        </dependency>

2.1 基于官网配置

首先先配置 issuer-uri ,这里指向是授权服务器的地址

# 授权服务器地址
spring.security.oauth2.resourceserver.jwt.issuer-uri= http://localhost:9000

关于过滤器链的配置:

@EnableWebSecurity
@Configuration(proxyBeanMethods = false)
public class ResourceServerConfig {

	// @formatter:off
	@Bean
	SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
		http
			.securityMatcher("/messages/**")
				.authorizeHttpRequests()
					.requestMatchers("/messages/**").hasAuthority("SCOPE_message.read")
					.and()
			.oauth2ResourceServer()
				.jwt();
		return http.build();
	}
	// @formatter:on

}

资源服务器将使用此 issuer-uri 进一步进行自我配置,发现授权服务器的公钥,并传入用于验证JWT的JwtDecoder。此过程的结果是授权服务器必须启动并接收请求才能使资源服务器成功启动。 

若如果资源服务器必须能够独立于授权服务器启动,那么可以提供jwk-set-uri。这将是我们进一步在OAuth2安全配置中添加属性:

# 资源服务器必须能够独立于授权服务器启动
spring.security.oauth2.resourceserver.jwt.jwk-set-uri= http://localhost:9000/oauth2/jwks

至此,资源服务器可以正常使用。若是你的系统比较庞大,每次请求都会请求授权服务器,这会给授权服务器带来压力,具体的实现方案可以根据实际情况而定。

2.2 确定加密方式

授权服务器的操作:

# JWK 配置
cloud:
  jwk:
    rsa:
      # 公钥
      public-key: MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzt2qx7HwpblnbwtRV9ZiaXwvUO4JlOYYVFEDmINxp5d+Nbih8hmOrlM+4qhr5Ej1Gc+D+TJ2oNoN/wtUaGP38Kf21UhiEbRedRfdQvOEuDXmScLUBd4tJ9dH4+i5XFSnkZi3L0rlTmPLpv8SuJSnNg/POjxmBxBAnJq4qmm2c7bXqcXOa8oAQYMtBHtuA6hhbbD2tpZEr4tM010eDPrZysFeVKNFlNV9fgBL5H2s7GRqVslHEmU6vQfQGCXL2Z+jDv8WH3k3kneV7EL24IipMDjmPzxk5zw6L8uzKxANuLVnh3mCDkqnaPMN4TBTSqE5muKR5SHyGF0/dqxodmanWwIDAQAB
      # 私钥
      private-key: MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDO3arHsfCluWdvC1FX1mJpfC9Q7gmU5hhUUQOYg3Gnl341uKHyGY6uUz7iqGvkSPUZz4P5Mnag2g3/C1RoY/fwp/bVSGIRtF51F91C84S4NeZJwtQF3i0n10fj6LlcVKeRmLcvSuVOY8um/xK4lKc2D886PGYHEECcmriqabZzttepxc5rygBBgy0Ee24DqGFtsPa2lkSvi0zTXR4M+tnKwV5Uo0WU1X1+AEvkfazsZGpWyUcSZTq9B9AYJcvZn6MO/xYfeTeSd5XsQvbgiKkwOOY/PGTnPDovy7MrEA24tWeHeYIOSqdo8w3hMFNKoTma4pHlIfIYXT92rGh2ZqdbAgMBAAECggEAHBX2GbO70lGdofLIQfk466JxLXc2tNEX94aiStgkcQESoR+RWTSFbdSejUPEQOkeNzljQnef/znBEbdg5+VpZHKhgsFCPgNzmZ6Pq1yIUJb8zldAgGVy/bLvBJn0ZKftB57+K/0VV0hu/hwpLLH+ESB3Xaw/8UXlx9KtL3Hifst94yMNh2+g1qHK7BIBxVlZmm8y137lt/ZJCCKf7zDOBFFmm/Hy71K7C6uOGmRmJ7Thq7f2dJx8iecPvMv7Bzd+LzvuZdJjowZkzMXPv85hUEpbToEQUHt4FReWWk87OUSRaXUZVONZvzUHMrYqN84tvONSa+swnxGWvjK2rRcSdQKBgQDyFeqQGPzJQY2u0rhMuj12yDTssSV7xagw88KYkaWpireuSEjxJpIEhRxjO3Ow0TYvZM9t7g/6gvuYh30/FIND4AwAuRtjAjKzXfOlIG7dJMBEk5yY1tloGwxak8sa8z+H+jw9cJik+X5j6MULNzUb709UPgMstxEVrCfhgEal/QKBgQDawYXIq1q43qIuFdjFOnZ6qBHtqWtIi8lZcOSUtPuqivIVSJt7AnkNhR9MfhkgaEuoL55wBR0BA+DoZWFmObgi5Y+Udb2+nlZVufY/ksNyZ1i+4ITKhzns7qjG2W0KMh7MG0biNbTtBy54WQp+Myog1UbuXMqyMSIunwRhOC5WNwKBgQDaDK+IN1mJlUgezaI/SgkOsmopP645e+Fwpj8C2T1UJqQnkOhSfaFL/PGC2AvumaKqsay8oY823z/rNS604K8TNfzZseFfHp24Pcm1VC9HdVDQ8/w7FlogkSxhcXmhvrPcsKIN3RtAjZEwQHsrDQEDNlxHzsthPUtgL/6D+NypqQKBgQDWN2Y8ENkBajrk6E3jLZHyIP2Vfy9o1kJxTKT6npRH+FKB1x0yg0Rpoe/5Zw5R9vAHncIILmmtoc+vo/+SLHmN6sEEf5w0uzcOMdHbhWvRbzSvjotbDLsDst4iA67MqjIQa7GpOTCYYEz4WzF0TcQ2bMRODR4NCyJPBzcxwONXVwKBgH8iJJtdmftjFqOkqNLT6XzLdPE4grkSzd2/RGiK003L3n0CxE2UqzNW/oSikAO5Jc/Tsxv6FtL9o/0Kjhut05C96Ku1oJfm7QI9ORSgCl/9Lv97GMw4E9nCTsgXqND6FMI7UqdgywpAo2hJSyE7N4vieulSJWJd5GaW/ubILwAM

将配置的公钥私钥加载到bean中,如下:

 @Autowired
    private JwkKeyProperties jwkKeyProperties;

    @Bean
    public JWKSource<SecurityContext> jwkSource() {
        RSAKey rsaKey = new RSAKey.Builder(jwkKeyProperties.rsaPublicKey())
                .privateKey(jwkKeyProperties.privateKey())
                .build();
        JWKSet jwkSet = new JWKSet(rsaKey);
        return new ImmutableJWKSet<>(jwkSet);
    }

至此,授权服务器固定好公钥私钥后,我们将这些公钥、私钥用到资源服务器,如下:

# JWK 配置
cloud:
  jwk:
    rsa:
      # 公钥
      public-key: MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzt2qx7HwpblnbwtRV9ZiaXwvUO4JlOYYVFEDmINxp5d+Nbih8hmOrlM+4qhr5Ej1Gc+D+TJ2oNoN/wtUaGP38Kf21UhiEbRedRfdQvOEuDXmScLUBd4tJ9dH4+i5XFSnkZi3L0rlTmPLpv8SuJSnNg/POjxmBxBAnJq4qmm2c7bXqcXOa8oAQYMtBHtuA6hhbbD2tpZEr4tM010eDPrZysFeVKNFlNV9fgBL5H2s7GRqVslHEmU6vQfQGCXL2Z+jDv8WH3k3kneV7EL24IipMDjmPzxk5zw6L8uzKxANuLVnh3mCDkqnaPMN4TBTSqE5muKR5SHyGF0/dqxodmanWwIDAQAB
      # 私钥
      private-key: MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDO3arHsfCluWdvC1FX1mJpfC9Q7gmU5hhUUQOYg3Gnl341uKHyGY6uUz7iqGvkSPUZz4P5Mnag2g3/C1RoY/fwp/bVSGIRtF51F91C84S4NeZJwtQF3i0n10fj6LlcVKeRmLcvSuVOY8um/xK4lKc2D886PGYHEECcmriqabZzttepxc5rygBBgy0Ee24DqGFtsPa2lkSvi0zTXR4M+tnKwV5Uo0WU1X1+AEvkfazsZGpWyUcSZTq9B9AYJcvZn6MO/xYfeTeSd5XsQvbgiKkwOOY/PGTnPDovy7MrEA24tWeHeYIOSqdo8w3hMFNKoTma4pHlIfIYXT92rGh2ZqdbAgMBAAECggEAHBX2GbO70lGdofLIQfk466JxLXc2tNEX94aiStgkcQESoR+RWTSFbdSejUPEQOkeNzljQnef/znBEbdg5+VpZHKhgsFCPgNzmZ6Pq1yIUJb8zldAgGVy/bLvBJn0ZKftB57+K/0VV0hu/hwpLLH+ESB3Xaw/8UXlx9KtL3Hifst94yMNh2+g1qHK7BIBxVlZmm8y137lt/ZJCCKf7zDOBFFmm/Hy71K7C6uOGmRmJ7Thq7f2dJx8iecPvMv7Bzd+LzvuZdJjowZkzMXPv85hUEpbToEQUHt4FReWWk87OUSRaXUZVONZvzUHMrYqN84tvONSa+swnxGWvjK2rRcSdQKBgQDyFeqQGPzJQY2u0rhMuj12yDTssSV7xagw88KYkaWpireuSEjxJpIEhRxjO3Ow0TYvZM9t7g/6gvuYh30/FIND4AwAuRtjAjKzXfOlIG7dJMBEk5yY1tloGwxak8sa8z+H+jw9cJik+X5j6MULNzUb709UPgMstxEVrCfhgEal/QKBgQDawYXIq1q43qIuFdjFOnZ6qBHtqWtIi8lZcOSUtPuqivIVSJt7AnkNhR9MfhkgaEuoL55wBR0BA+DoZWFmObgi5Y+Udb2+nlZVufY/ksNyZ1i+4ITKhzns7qjG2W0KMh7MG0biNbTtBy54WQp+Myog1UbuXMqyMSIunwRhOC5WNwKBgQDaDK+IN1mJlUgezaI/SgkOsmopP645e+Fwpj8C2T1UJqQnkOhSfaFL/PGC2AvumaKqsay8oY823z/rNS604K8TNfzZseFfHp24Pcm1VC9HdVDQ8/w7FlogkSxhcXmhvrPcsKIN3RtAjZEwQHsrDQEDNlxHzsthPUtgL/6D+NypqQKBgQDWN2Y8ENkBajrk6E3jLZHyIP2Vfy9o1kJxTKT6npRH+FKB1x0yg0Rpoe/5Zw5R9vAHncIILmmtoc+vo/+SLHmN6sEEf5w0uzcOMdHbhWvRbzSvjotbDLsDst4iA67MqjIQa7GpOTCYYEz4WzF0TcQ2bMRODR4NCyJPBzcxwONXVwKBgH8iJJtdmftjFqOkqNLT6XzLdPE4grkSzd2/RGiK003L3n0CxE2UqzNW/oSikAO5Jc/Tsxv6FtL9o/0Kjhut05C96Ku1oJfm7QI9ORSgCl/9Lv97GMw4E9nCTsgXqND6FMI7UqdgywpAo2hJSyE7N4vieulSJWJd5GaW/ubILwAM

接下来是资源服务器的过滤器链配置:

@EnableGlobalMethodSecurity(prePostEnabled=true)
@EnableWebSecurity
@Configuration
public class ResourceServerConfig {

//	@Value("${spring.security.oauth2.resourceserver.jwt.issuer-uri}")
	String issuerUri;

	@Autowired
	private JwkKeyProperties jwkKeyProperties;

	@Bean
	SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
		http
				.authorizeHttpRequests((authorize) -> authorize
						// SecurityConstant.IGNORE_PERM_URLS 不需要权限认证
						.requestMatchers(RedisOAuth2Constant.IGNORE_PERM_URLS).permitAll()
						// 其他的需要权限认证
						.anyRequest().authenticated()
				)
		// 资源服务配置秘钥
		.oauth2ResourceServer().jwt(oauth2ResourceServer -> {
			RSAPublicKey rsaPublicKey = jwkKeyProperties.rsaPublicKey();
			NimbusJwtDecoder.PublicKeyJwtDecoderBuilder publicKeyJwtDecoderBuilder = NimbusJwtDecoder
					.withPublicKey(rsaPublicKey);
			NimbusJwtDecoder nimbusJwtDecoder = publicKeyJwtDecoderBuilder.build();
			oauth2ResourceServer.decoder(nimbusJwtDecoder);
			// 解析jwt
			oauth2ResourceServer.jwtAuthenticationConverter(getJwtToUserAuthenticationConverter());
		});
		return http.build();
	}

	public JwtToUserAuthenticationConverter getJwtToUserAuthenticationConverter(){
		return new JwtToUserAuthenticationConverter();
	}

}

每次请求资源服务器的时候,手动根据公钥解析、转行jwt。这时候需要实现 Converter 接口,实现如下:

@Slf4j
//@Component
public class JwtToUserAuthenticationConverter implements Converter<Jwt, UsernamePasswordAuthenticationToken> {

    @Override
    public UsernamePasswordAuthenticationToken convert(@NotNull Jwt jwt) {
        System.out.println("------"+ JSON.toJSONString(jwt));
        /**
         * 方案一:从 jwt 中的 claims - >authorities 获取权限信息
         * 方案二: 根据 jwt.getSubject() 登录名去查数据库对应的用户权限
         */

        CustomUserDetails details =  new CustomUserDetails();
        // todo 调用用户接口
        String subject = jwt.getSubject();
        log.info("从jwt获取的用户名:{}",subject);
        details.setUsername(subject);
        /**
         * hasRole  对应的是 ROLE_admin
         * hasAuthority 对应的是 user:list
         *
         * 在做权限的时候需要注意 security 权限前缀
         */
        details.setRoles(List.of("admin","user:list","user"));
        return new UsernamePasswordAuthenticationToken(details, jwt, details.getAuthorities());
    }

}

至此,资源服务器的授权操作及jwt的解析完成。

3、结论

不管根据哪种方案实现,其实都需要了解授权过程。也就是授权(token中存放用户名、授权信息),接着资源服务器的token处理过程,可以直接请求授权服务器,由授权服务器验证;也可以在授权服务器确定固定的公钥私钥,资源服务器自己根据公钥解析token,获取jwt,最后获取用户信息。

以上的源码来源自己开源项目:

oauth2-resource资源服务器

oauth2-server 授权服务器

### Spring Security OAuth2 配置指南 #### 1. 授权服务器 (Authorization Server) 为了配置授权服务器,可以使用 `spring-security-oauth2-authorization-server` 提供的功能。以下是具体的步骤: 引入必要的依赖项: ```xml <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-oauth2-authorization-server</artifactId> <version>1.0.0</version> </dependency> ``` 创建一个类来启用授权服务器功能并定义令牌端点和其他必要设置: ```java 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.core.userdetails.UserDetailsService; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.oauth2.server.authorization.config.ProviderSettings; @Configuration(proxyBeanMethods = false) public class AuthorizationServerConfig { @Bean public ProviderSettings providerSettings() { return ProviderSettings.builder() .issuer("https://example.com") // 设置发行者URL .build(); } protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests(authorize -> authorize.anyRequest().authenticated()) .oauth2ResourceServer(OAuth2ResourceServerConfigurer::jwt); } } ``` 上述代码片段展示了如何通过自定义 `ProviderSettings` 来指定授权服务器的相关参数[^1]。 --- #### 2. 客户端 (Client Configuration) 要使应用程序作为OAuth2客户端运行,需添加以下依赖项: ```xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-oauth2-client</artifactId> </dependency> ``` 在 `application.yml` 或 `application.properties` 文件中提供客户端的具体配置信息: ```yaml spring: security: oauth2: client: registration: google: clientId: your-google-client-id clientSecret: your-google-client-secret redirectUri: "{baseUrl}/login/oauth2/code/{registrationId}" scope: - email - profile provider: google: authorization-uri: https://accounts.google.com/o/oauth2/v2/auth token-uri: https://www.googleapis.com/oauth2/v4/token user-info-uri: https://www.googleapis.com/oauth2/v3/userinfo jwk-set-uri: https://www.googleapis.com/oauth2/v3/certs ``` 此部分描述了如何注册外部身份提供商(如Google),以及如何获取用户的电子邮件和个人资料数据[^2]。 --- #### 3. 资源服务器 (Resource Server) 资源服务器负责验证传入请求中的访问令牌,并保护受控API免遭未经授权的访问。为此,应加入如下依赖: ```xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-oauth2-resource-server</artifactId> </dependency> ``` 接着,在安全配置文件中声明资源服务器的行为模式: ```java 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 resourceServerSecurityFilterChain(HttpSecurity http) throws Exception { http.authorizeHttpRequests(authz -> authz .anyRequest().authenticated()) .oauth2ResourceServer(oauth2 -> oauth2.jwt()); return http.build(); } } ``` 这里说明的是如何利用JWT解析器对进入系统的每一个HTTP请求执行认证操作[^3]。 --- #### 总结 以上分别介绍了基于Spring Boot框架下构建OAuth2架构所需的三个核心模块——授权服务器、客户端和资源服务器的基础搭建方法及其相互协作方式。每一步都紧密关联着实际项目开发过程中的需求场景和技术选型考量因素。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值