jwk-set-uri

763 阅读5分钟

这个配置是 Spring Security 用于配置 OAuth 2.0 资源服务器的 JWT(JSON Web Token)设置。具体来说,它配置了资源服务器如何验证 JWT 令牌。

配置项解释

  • spring.security.oauth2.resourceserver.jwt.jwk-set-uri:这个配置项指定了 JWT 的 JWK(JSON Web Key)集合的 URI。资源服务器会从这个 URI 获取公钥,用于验证 JWT 的签名。

详细解释

spring.security.oauth2.resourceserver

这个配置项启用 Spring Security 的 OAuth 2.0 资源服务器支持。资源服务器是指那些需要保护的 API 服务,它们会验证传入请求中的访问令牌(Access Token)。

jwt

这个配置项启用 JWT 令牌的支持。JWT 是一种紧凑的、URL 安全的令牌格式,广泛用于身份验证和信息交换。

jwk-set-uri

这个配置项指定了一个 URI,资源服务器会从这个 URI 获取 JWK 集合。JWK 是一种 JSON 数据结构,表示一组加密密钥。资源服务器使用这些密钥来验证 JWT 的签名。

示例配置

假设你的身份提供者(Identity Provider, IdP)公开了一个 JWK 集合的 URI,你可以在 application.yml 中进行如下配置:

spring:
  security:
    oauth2:
      resourceserver:
        jwt:
          jwk-set-uri: https://your-identity-provider.com/.well-known/jwks.json

工作原理

  1. 获取 JWK 集合:资源服务器启动时,会从配置的 jwk-set-uri 获取 JWK 集合。这些 JWK 包含了用于验证 JWT 签名的公钥。
  2. 验证 JWT:当资源服务器收到请求时,会从请求头中提取 JWT 令牌,并使用 JWK 集合中的公钥验证 JWT 的签名。
  3. 解析 JWT:如果 JWT 签名验证通过,资源服务器会解析 JWT,提取其中的声明(claims),如用户信息、权限等。
  4. 授权访问:根据 JWT 中的声明,资源服务器决定是否授权访问受保护的资源。

示例代码

以下是一个简单的 Spring Boot 应用程序,配置了 JWT 资源服务器:

application.yml
spring:
  security:
    oauth2:
      resourceserver:
        jwt:
          jwk-set-uri: https://your-identity-provider.com/.well-known/jwks.json
SecurityConfig.java
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests(authorizeRequests ->
                authorizeRequests
                    .antMatchers("/public/**").permitAll()
                    .anyRequest().authenticated()
            )
            .oauth2ResourceServer(oauth2ResourceServer ->
                oauth2ResourceServer
                    .jwt()
            );
    }
}

总结

spring.security.oauth2.resourceserver.jwt.jwk-set-uri 配置项用于指定资源服务器从哪里获取 JWK 集合,以便验证 JWT 令牌的签名。通过这个配置,资源服务器可以确保传入的 JWT 令牌是由可信的身份提供者签发的,并且未被篡改。

org.springframework.security.oauth2.jwt.NimbusReactiveJwtDecoder 是 Spring Security 提供的一个类,用于解码和验证 JWT(JSON Web Token)。它是基于 Nimbus JOSE + JWT 库实现的,支持响应式编程模型。

主要功能

NimbusReactiveJwtDecoder 类的主要功能是解码和验证 JWT。它可以从 JWT 中提取声明(claims),并验证 JWT 的签名和有效性。

主要方法

  • decode(String token) :解码和验证给定的 JWT 令牌,返回一个 Mono<Jwt>,其中包含解码后的 JWT 对象。

构造方法

NimbusReactiveJwtDecoder 提供了多种构造方法,允许使用不同的方式来配置解码器:

  1. 使用 JWK Set URI

    public static NimbusReactiveJwtDecoder withJwkSetUri(String jwkSetUri)
    
  2. 使用公钥

    public static NimbusReactiveJwtDecoder withPublicKey(RSAPublicKey key)
    
  3. 使用密钥对

    public static NimbusReactiveJwtDecoder withSecretKey(SecretKey secretKey)
    

示例代码

以下是一个使用 NimbusReactiveJwtDecoder 解码和验证 JWT 的示例代码:

使用 JWK Set URI
import org.springframework.security.oauth2.jwt.Jwt;
import org.springframework.security.oauth2.jwt.JwtDecoder;
import org.springframework.security.oauth2.jwt.NimbusReactiveJwtDecoder;
import reactor.core.publisher.Mono;

public class JwtDecoderExample {

    public static void main(String[] args) {
        String jwkSetUri = "https://your-identity-provider.com/.well-known/jwks.json";
        NimbusReactiveJwtDecoder jwtDecoder = NimbusReactiveJwtDecoder.withJwkSetUri(jwkSetUri).build();

        String token = "your-jwt-token";
        Mono<Jwt> jwtMono = jwtDecoder.decode(token);

        jwtMono.subscribe(jwt -> {
            System.out.println("JWT Claims: " + jwt.getClaims());
        }, error -> {
            System.err.println("Failed to decode JWT: " + error.getMessage());
        });
    }
}
使用公钥
import org.springframework.security.oauth2.jwt.Jwt;
import org.springframework.security.oauth2.jwt.JwtDecoder;
import org.springframework.security.oauth2.jwt.NimbusReactiveJwtDecoder;
import reactor.core.publisher.Mono;

import java.security.interfaces.RSAPublicKey;
import java.security.KeyFactory;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;

public class JwtDecoderExample {

    public static void main(String[] args) throws Exception {
        String publicKeyPEM = "your-public-key-pem";
        byte[] decoded = Base64.getDecoder().decode(publicKeyPEM);
        X509EncodedKeySpec spec = new X509EncodedKeySpec(decoded);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        RSAPublicKey publicKey = (RSAPublicKey) keyFactory.generatePublic(spec);

        NimbusReactiveJwtDecoder jwtDecoder = NimbusReactiveJwtDecoder.withPublicKey(publicKey).build();

        String token = "your-jwt-token";
        Mono<Jwt> jwtMono = jwtDecoder.decode(token);

        jwtMono.subscribe(jwt -> {
            System.out.println("JWT Claims: " + jwt.getClaims());
        }, error -> {
            System.err.println("Failed to decode JWT: " + error.getMessage());
        });
    }
}

集成到 Spring Security 配置

你可以将 NimbusReactiveJwtDecoder 集成到 Spring Security 的配置中,以便在资源服务器中使用:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity;
import org.springframework.security.config.web.server.ServerHttpSecurity;
import org.springframework.security.oauth2.jwt.ReactiveJwtDecoder;
import org.springframework.security.web.server.SecurityWebFilterChain;

@Configuration
@EnableWebFluxSecurity
public class SecurityConfig {

    @Bean
    public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) {
        http
            .authorizeExchange(exchanges -> exchanges
                .pathMatchers("/public/**").permitAll()
                .anyExchange().authenticated()
            )
            .oauth2ResourceServer(oauth2 -> oauth2
                .jwt(jwt -> jwt
                    .jwtDecoder(jwtDecoder())
                )
            );
        return http.build();
    }

    @Bean
    public ReactiveJwtDecoder jwtDecoder() {
        String jwkSetUri = "https://your-identity-provider.com/.well-known/jwks.json";
        return NimbusReactiveJwtDecoder.withJwkSetUri(jwkSetUri).build();
    }
}

总结

NimbusReactiveJwtDecoder 是 Spring Security 提供的一个类,用于解码和验证 JWT。它支持响应式编程模型,并基于 Nimbus JOSE + JWT 库实现。通过配置 JWK Set URI、公钥或密钥对,可以灵活地使用 NimbusReactiveJwtDecoder 来验证 JWT 的签名和有效性。

QA 1

Question

这里的 jwk-set-uri 应该配置的文件是从哪来的?

Answer

jwk-set-uri 配置项指定了一个 URI,资源服务器会从这个 URI 获取 JSON Web Key (JWK) 集合。这个 URI 通常由身份提供者(Identity Provider, IdP)提供,用于公开其公钥信息,以便客户端和资源服务器可以验证 JWT 的签名。

JWK Set URI 的来源

  1. 身份提供者的配置:大多数现代身份提供者(如 Auth0、Okta、Azure AD、Google Identity Platform 等)都会公开一个 JWK Set URI,用于发布其公钥信息。这个 URI 通常遵循 OpenID Connect (OIDC) 规范,并且在 .well-known 路径下可以找到。

  2. OpenID Connect 发现文档:如果身份提供者支持 OpenID Connect 规范,它通常会提供一个发现文档(Discovery Document),其中包含 JWK Set URI。发现文档的 URI 通常是:

    https://<identity-provider-domain>/.well-known/openid-configuration
    

    你可以访问这个 URI,查看发现文档,其中会包含 jwks_uri 字段,指向 JWK Set URI。

示例

假设你使用的是 Auth0 作为身份提供者,Auth0 的 JWK Set URI 通常是:

https://<your-auth0-domain>/.well-known/jwks.json

你可以在浏览器中访问这个 URI,查看 JWK 集合。JWK 集合是一个 JSON 对象,包含一个或多个 JWK,每个 JWK 表示一个公钥。

如何找到 JWK Set URI

  1. 查看身份提供者文档:大多数身份提供者的文档中会明确说明 JWK Set URI 的位置。
  2. OpenID Connect 发现文档:如果身份提供者支持 OpenID Connect,可以访问发现文档,查找 jwks_uri 字段。

总结

jwk-set-uri 配置项指定了一个 URI,资源服务器会从这个 URI 获取 JWK 集合,用于验证 JWT 的签名。这个 URI 通常由身份提供者提供,并且可以在身份提供者的文档或 OpenID Connect 发现文档中找到。通过正确配置 jwk-set-uri,资源服务器可以确保 JWT 的签名是由可信的身份提供者签发的,并且未被篡改。