[英]Does I need a spring boot oauth2 authorization server to generate a custom JWT and a JWKS endpoint?
[英]How can OAuth2 resource server use endpoint to access public key when I add custom jwt details to the authorization server?
我自定义了授权服务器以将自定义详细信息添加到 JSON Web 令牌,并希望资源服务器应该使用端点访问授权服务器上的验证者公钥。 但是OAuth2AuthenticationDetails.getDecodedDetails()
返回null
。 我的代码结构如下所示:
自定义令牌增强器 class:
public class CustomTokenEnhancer implements TokenEnhancer {
@Override
public OAuth2AccessToken enhance(OAuth2AccessToken oauth2AccessToken,
OAuth2Authentication oauth2Authentication) {
var customToken = new DefaultOAuth2AccessToken(oauth2AccessToken);
Map<String, Object> customInfo = Map.of("generatedIn", "Year "+LocalDateTime.now().getYear());
customToken.setAdditionalInformation(customInfo);
return customToken;
}
}
授权服务器 class:
@Configuration
@EnableAuthorizationServer
public class AuthServerConfig extends AuthorizationServerConfigurerAdapter{
@Value("${password}")
private String password;
@Value("${privateKey}")
private String privateKey;
@Value("${alias}")
private String alias;
//autowire the authentication manager here
@Autowired
private AuthenticationManager authenticationManager;
//provide clients' details
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("client")
.secret("secret")
.authorizedGrantTypes("password", "refresh_token")
.scopes("read")
.and()
.withClient("resourceserver")
.secret("resourceserversecret");
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
//Define a token enhancer chain here
TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();
//Add the two token enhancer objects to a list
var tokenEnhancers =
List.of(new CustomTokenEnhancer(), jwtAccessTokenConverter());
//Add the token enhancer list to the chain of token enhancer
tokenEnhancerChain.setTokenEnhancers(tokenEnhancers);
endpoints.authenticationManager(authenticationManager)
.tokenStore(tokenStore())
.tokenEnhancer(tokenEnhancerChain);
}
@Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
/*
* Configures the authorization server to expose and endpoint for
* public key for any authenticated
* request with valid client credentials
*/
security.tokenKeyAccess("isAuthenticated()");
}
@Bean
public TokenStore tokenStore() {
return new JwtTokenStore(jwtAccessTokenConverter());
}
@Bean
public JwtAccessTokenConverter jwtAccessTokenConverter() {
var converter = new JwtAccessTokenConverter();
KeyStoreKeyFactory keyStoreKeyFactory =
new KeyStoreKeyFactory(
new ClassPathResource(privateKey),
password.toCharArray()
);
converter.setKeyPair(keyStoreKeyFactory.getKeyPair(alias));
return converter;
}
}
应用程序.properties 文件:
password = somepassword
privateKey =key.jks
alias = somekey
资源服务器:
@Configuration
@EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
}
应用程序.properties 文件:
server.port = 9090
security.oauth2.resource.jwt.key-uri=http://localhost:8080/oauth/token_key
security.oauth2.client.client-id=resourceserver
security.oauth2.client.client-secret=resourceserversecret
资源服务器上的受保护端点:
@RestController
public class HelloController {
@GetMapping("/hello")
public String hello(OAuth2Authentication authentication) {
OAuth2AuthenticationDetails details =
(OAuth2AuthenticationDetails) authentication.getDetails();
return details.getDecodedDetails().toString();
}
}
当我发出curl
请求时,调用details.getDecodedDetails().toString()
的结果将null
打印到控制台: curl -H "Authorization:Bearer e1yhrjkkkfk....." http://localhost:9090/hello
。
但是,如果我像这样实现资源服务器,代码将按预期运行:
@Configuration
@EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter{
@Value("${publicKey}") //from the properties file
private String publicKey;
@Override
public void configure(ResourceServerSecurityConfigurer resources) {
}
@Bean
public TokenStore tokenStore() {
return new JwtTokenStore(jwtAccessTokenConverter());
}
@Bean
public JwtAccessTokenConverter jwtAccessTokenConverter() {
var converter = new OtherAccessTokenConverter(); //Handles the claims in our custom token.
converter.setVerifierKey(publicKey);
return converter;
}
}
其他AccessTokenConverter class:
public class OtherAccessTokenConverter extends JwtAccessTokenConverter {
@Override
public OAuth2Authentication extractAuthentication(Map<String, ?> map) {
//Get the initial authenticated object
var authentication = super.extractAuthentication(map);
//Add the custom details to the authentication object
authentication.setDetails(map);
//Return the authentication object
return authentication;
}
但我从来不想在资源服务器上拥有公共验证器密钥,而是通过端点访问。 我怎么go一下呢?
spring-boot-starter-oauth2-resource-server
依赖项:<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
</dependency>
您使用的是什么版本的 spring 引导 + spring 安全? 我问的原因是因为一旦你有了上面的依赖,你就不需要显式地包含@EnableResourceServer
。
spring.security.oauth2.resourceserver.jwt.jwk-set-uri=http://openam.localtest.me:8080/openam/oauth2/realms/subrealm/connect/jwk_uri
注意:我还注意到您缺少spring.
属性文件中的前缀?
这是您唯一需要做的两件事。 无需手动覆盖 Spring Boot 的startup
模块提供的默认值。
然后会发生的是,一旦您的 Web / REST 端点收到带有Bearer
令牌的 HTTP Authorization
header ......并且......承载令牌是签名的 JWT,资源服务器将:
spring.security.oauth2.resourceserver.jwt.jwk-set-uri
属性指定的URL。kid
具有相同kid
的公钥。 我有点在同一个旅程中,我必须使公钥可见,以某种方式列在资源服务器的application.properties
文件中定义的 URL 中,指向 ForgeRock AM 的connect/jwk_uri
...但是我添加的公钥JWK Set of ForgeRock AM's trusted JWT issuer does not appear in the connect/jwk_uri
URL when queries from a browser / curl.
似乎 Spring 安全资源服务器支持 JWT 不记名令牌授权,如 Spring 安全文档 URL 中强调的那样:
https://docs.spring.io/spring-security/reference/5.7/servlet/oauth2/resource-server/jwt.html
...与 ForgeRock AM 的预期不兼容。
例如:
SpringBoot OAuth2 资源服务器在接收签名 JWT 作为Authorization
HTTP header 中的承载者时期望以下内容:
Authorization
HTTP header 请求中将已签署的 JWT 作为承载令牌发送到资源服务器,授予类型为urn:ietf:params:oauth:grant-type:jwt-bearer
。spring.security.oauth2.resourceserver.jwt.jwk-set-uri
属性中查找匹配的公钥。 (您也可以尝试首先从spring.security.oauth2.resourceserver.jwt.public-key-location
在本地加载它们 - 这个应该是 PEM 格式。)而 ForgeRock AM 的 model 期望不同的流程(此处记录: https://backstage.forgerock.com/docs/am/7.2/oauth2-guide/oauth2-jwt-bearer-grant.html )
因此,您在资源服务器的application.properties
中更改以下内容,如下所示:
spring.security.oauth2.resourceserver.opaque-token.introspection-uri=http://openam.localtest.me:8080/openam/oauth2/realms/subrealm/introspect
spring.security.oauth2.resourceserver.opaque-token.client-id=someclient
spring.security.oauth2.resourceserver.opaque-token.client-secret=somesecret
... 然后删除/注释掉与 jwk / jwt 相关的其他属性。(例如注释掉spring.security.oauth2.resourceserver.jwt.jwk-set-uri
)
Authorization
HTTP header 请求中将已签署的 JWT 作为承载令牌发送到 ForgeRock 授权服务器,授权类型为urn:ietf:params:oauth:grant-type:jwt-bearer
因此预计ForgeRock AM的可信JWT issuer agent已经在上一步配置了signer的公钥JWKS。Authorization
HTTP header 请求中向资源服务器(例如 Spring 的 OAuth2 资源服务器)发送并使用此不透明访问令牌作为承载令牌。spring.security.oauth2.resourceserver.opaque-token.introspection-uri
),这是 AM 服务器公开的端点,用于验证访问令牌. 因此(无法包含我添加到 ForgeRock AM 的connect/jwk_uri
的 HTTP output 中的公钥,我现在希望遵循 ForgeRock AM 记录的授权流程。
此外,文档位于:
https://docs.spring.io/spring-security/reference/5.7/servlet/oauth2/resource-server/jwt.html
.. 表示您需要明确包含spring-security-oauth2-resource-server
和spring-security-oauth2-jose
以支持已签名的 JWT。但是 maven 依赖树表明它被自动包含为传递依赖:
$ mvn dependency:tree -Dincludes=org.springframework.security:spring-security-oauth2-jose:jar
[INFO] Scanning for projects...
[INFO]
[INFO] ---------------< org.example.oauth2-resource-server:jwt >---------------
[INFO] Building oauth2-resource-server 0.0.1-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- maven-dependency-plugin:3.3.0:tree (default-cli) @ jwt ---
[INFO] org.example.oauth2-resource-server:jwt:jar:0.0.1-SNAPSHOT
[INFO] \- org.springframework.boot:spring-boot-starter-oauth2-resource-server:jar:2.7.7:compile
[INFO] \- org.springframework.security:spring-security-oauth2-jose:jar:5.7.6:compile
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 0.629 s
[INFO] Finished at: 2023-01-01T14:33:49+11:00
[INFO] ------------------------------------------------------------------------
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.