为什么我的令牌被拒绝?什么是资源 ID? "Invalid token does not contain resource id (oauth2-resource)"
Why is my token being rejected? What is a resource ID? "Invalid token does not contain resource id (oauth2-resource)"
我正在尝试为 spring 项目配置 OAuth2。我正在使用我的工作场所提供的共享 UAA (oauth implementation from cloud foundry) 实例(因此我没有尝试创建授权服务器,并且授权服务器与资源服务器是分开的)。前端是一个 single-page-application,它使用隐式授权直接从授权服务器获取令牌。我有 SPA 设置,它在每个 Web API 调用微服务时添加 Authorization: Bearer <TOKEN>
header。
我现在的问题是微服务。
我正在尝试使用此共享授权服务器来验证微服务。我在这里可能有一个误解,买我目前的理解是这些微服务扮演资源服务器的角色,因为它们托管 SPA 用来获取数据的端点。
所以我尝试像这样配置微服务:
@Configuration
@EnableResourceServer
public class OAuth2ResourceServerConfig extends ResourceServerConfigurerAdapter {
@Override
public void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests()
.antMatchers("/api/**").authenticated();
}
@Bean
public TokenStore tokenStore() {
return new JwtTokenStore(accessTokenConverter());
}
@Bean
public JwtAccessTokenConverter accessTokenConverter() {
JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
converter.setVerifierKey("-----BEGIN PUBLIC KEY-----<key omitted>-----END PUBLIC KEY-----");
return converter;
}
@Bean
@Primary
public DefaultTokenServices tokenServices() {
DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
defaultTokenServices.setTokenStore(tokenStore());
return defaultTokenServices;
}
@Override
public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
resources.tokenServices(tokenServices());
}
}
现在,每当我用 Authorization: Bearer <TOKEN>
命中 /api/**
时,我都会得到 403
并出现以下错误:
{
"error": "access_denied",
"error_description": "Invalid token does not contain resource id (oauth2-resource)"
}
所以这是我的问题:
- 如何配置这些微服务来验证令牌并插入
Principal
in controller methods? I currently have it setup where the SPA has and sends the token and I also have the public key used to verify the signature of the token. I have also used jwt.io 来测试令牌,它显示 "Signature Verified".
- 什么是资源 ID?为什么我需要它,为什么会导致上面的错误?那是 Spring 唯一的事情吗?
谢谢!
Spring OAuth 需要 JWT 令牌中的 "aud" claim。该声明的值应与您在 Spring 应用中指定的 resourceId
值匹配(如果未指定,则默认为 "oauth2-resource")。
要解决您的问题,您需要:
1) 登录您共享的 UAA 并确保它包含 "aud" 声明。
2) 将 "aud" 声明的值更改为 "oauth2-resource" 或最好在您的 Spring 应用更新 resourceId
中更改为该声明的值,如下所示:
@Override
public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
resources.tokenServices(tokenServices());
resources.resourceId(value from the aud claim you got from UAA server);
}
我添加了一个类似的问题。就我而言,我使用了 jdbc 身份验证,我的授权服务器和资源服务器是两个独立的 API.
授权服务器
@Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer) {
oauthServer.tokenKeyAccess("permitAll()")
.checkTokenAccess("isAuthenticated()")
.passwordEncoder(oauthClientPasswordEncoder);
}
/**
* Define the client details service. The client may be define either as in memory or in database.
* Here client with be fetch from the specify database
*/
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.jdbc(dataSource);
}
/**
* Define the authorization by providing authentificationManager
* And the token enhancement
*/
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
endpoints.tokenStore(tokenStore())
.tokenEnhancer(getTokenEnhancer())
.authenticationManager(authenticationManager).userDetailsService(userDetailsService);
}
资源服务器
public class OAuth2ResourceServerConfig extends
ResourceServerConfigurerAdapter {
private TokenExtractor tokenExtractor = new BearerTokenExtractor();
@Autowired
private DataSource dataSource;
@Bean
public TokenStore tokenStore() {
return new JdbcTokenStore(dataSource);
}
@Override
public void configure(HttpSecurity http) throws Exception {
http.addFilterAfter(new OncePerRequestFilter() {
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException {
// We don't want to allow access to a resource with no token so clear
// the security context in case it is actually an OAuth2Authentication
if (tokenExtractor.extract(request) == null) {
SecurityContextHolder.clearContext();
}
filterChain.doFilter(request, response);
}
}, AbstractPreAuthenticatedProcessingFilter.class);
http.csrf().disable();
http.authorizeRequests().anyRequest().authenticated();
}
@Bean
public AccessTokenConverter accessTokenConverter() {
return new DefaultAccessTokenConverter();
}
@Bean
public RemoteTokenServices remoteTokenServices(final @Value("${auth.server.url}") String checkTokenUrl,
final @Value("${auth.resource.server.clientId}") String clientId,
final @Value("${auth.resource.server.clientsecret}") String clientSecret) {
final RemoteTokenServices remoteTokenServices = new RemoteTokenServices();
remoteTokenServices.setCheckTokenEndpointUrl(checkTokenUrl);
remoteTokenServices.setClientId(clientId);
remoteTokenServices.setClientSecret(clientSecret);
remoteTokenServices.setAccessTokenConverter(accessTokenConverter());
return remoteTokenServices;
}
有了这个配置,我得到了
{
"error": "access_denied",
"error_description": "Invalid token does not contain resource id
(xxxxx)"
}
为了解决这个问题,我不得不添加
private String resourceIds= "xxxxx". !! maked sure that this resourceids is store in oauth_client_details for the clientid I used to get the token
@Override
public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
resources.resourceId(resourceIds).tokenStore(tokenStore());
}
我在使用 spring 实现 oauth2.0 时遇到了同样的问题,这是我发现的关于 resourceid 的内容。
Spring Security OAuth2架构分为Authorization Server和Resource Server资源服务器。我们可以为每个 Resource Server(一个微服务实例)设置一个 ResourceID。 Authorization Server授权客户端时,可以设置客户端可以访问哪些Resource Server资源服务。
在授权服务器中为客户端配置ResourceID的目的是限制客户端可以访问的资源服务。
参考下面link设置ResourceID,
https://www.fatalerrors.org/a/resource-of-spring-security-oauth2_-id-configuration-and-verification.html
我正在尝试为 spring 项目配置 OAuth2。我正在使用我的工作场所提供的共享 UAA (oauth implementation from cloud foundry) 实例(因此我没有尝试创建授权服务器,并且授权服务器与资源服务器是分开的)。前端是一个 single-page-application,它使用隐式授权直接从授权服务器获取令牌。我有 SPA 设置,它在每个 Web API 调用微服务时添加 Authorization: Bearer <TOKEN>
header。
我现在的问题是微服务。
我正在尝试使用此共享授权服务器来验证微服务。我在这里可能有一个误解,买我目前的理解是这些微服务扮演资源服务器的角色,因为它们托管 SPA 用来获取数据的端点。
所以我尝试像这样配置微服务:
@Configuration
@EnableResourceServer
public class OAuth2ResourceServerConfig extends ResourceServerConfigurerAdapter {
@Override
public void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests()
.antMatchers("/api/**").authenticated();
}
@Bean
public TokenStore tokenStore() {
return new JwtTokenStore(accessTokenConverter());
}
@Bean
public JwtAccessTokenConverter accessTokenConverter() {
JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
converter.setVerifierKey("-----BEGIN PUBLIC KEY-----<key omitted>-----END PUBLIC KEY-----");
return converter;
}
@Bean
@Primary
public DefaultTokenServices tokenServices() {
DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
defaultTokenServices.setTokenStore(tokenStore());
return defaultTokenServices;
}
@Override
public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
resources.tokenServices(tokenServices());
}
}
现在,每当我用 Authorization: Bearer <TOKEN>
命中 /api/**
时,我都会得到 403
并出现以下错误:
{
"error": "access_denied",
"error_description": "Invalid token does not contain resource id (oauth2-resource)"
}
所以这是我的问题:
- 如何配置这些微服务来验证令牌并插入
Principal
in controller methods? I currently have it setup where the SPA has and sends the token and I also have the public key used to verify the signature of the token. I have also used jwt.io 来测试令牌,它显示 "Signature Verified". - 什么是资源 ID?为什么我需要它,为什么会导致上面的错误?那是 Spring 唯一的事情吗?
谢谢!
Spring OAuth 需要 JWT 令牌中的 "aud" claim。该声明的值应与您在 Spring 应用中指定的 resourceId
值匹配(如果未指定,则默认为 "oauth2-resource")。
要解决您的问题,您需要:
1) 登录您共享的 UAA 并确保它包含 "aud" 声明。
2) 将 "aud" 声明的值更改为 "oauth2-resource" 或最好在您的 Spring 应用更新 resourceId
中更改为该声明的值,如下所示:
@Override
public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
resources.tokenServices(tokenServices());
resources.resourceId(value from the aud claim you got from UAA server);
}
我添加了一个类似的问题。就我而言,我使用了 jdbc 身份验证,我的授权服务器和资源服务器是两个独立的 API.
授权服务器
@Override public void configure(AuthorizationServerSecurityConfigurer oauthServer) { oauthServer.tokenKeyAccess("permitAll()") .checkTokenAccess("isAuthenticated()") .passwordEncoder(oauthClientPasswordEncoder);
}
/** * Define the client details service. The client may be define either as in memory or in database. * Here client with be fetch from the specify database */ @Override public void configure(ClientDetailsServiceConfigurer clients) throws Exception { clients.jdbc(dataSource); } /** * Define the authorization by providing authentificationManager * And the token enhancement */ @Override public void configure(AuthorizationServerEndpointsConfigurer endpoints) { endpoints.tokenStore(tokenStore()) .tokenEnhancer(getTokenEnhancer()) .authenticationManager(authenticationManager).userDetailsService(userDetailsService); }
资源服务器
public class OAuth2ResourceServerConfig extends ResourceServerConfigurerAdapter { private TokenExtractor tokenExtractor = new BearerTokenExtractor(); @Autowired private DataSource dataSource; @Bean public TokenStore tokenStore() { return new JdbcTokenStore(dataSource); } @Override public void configure(HttpSecurity http) throws Exception { http.addFilterAfter(new OncePerRequestFilter() { @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { // We don't want to allow access to a resource with no token so clear // the security context in case it is actually an OAuth2Authentication if (tokenExtractor.extract(request) == null) { SecurityContextHolder.clearContext(); } filterChain.doFilter(request, response); } }, AbstractPreAuthenticatedProcessingFilter.class); http.csrf().disable(); http.authorizeRequests().anyRequest().authenticated(); } @Bean public AccessTokenConverter accessTokenConverter() { return new DefaultAccessTokenConverter(); } @Bean public RemoteTokenServices remoteTokenServices(final @Value("${auth.server.url}") String checkTokenUrl, final @Value("${auth.resource.server.clientId}") String clientId, final @Value("${auth.resource.server.clientsecret}") String clientSecret) { final RemoteTokenServices remoteTokenServices = new RemoteTokenServices(); remoteTokenServices.setCheckTokenEndpointUrl(checkTokenUrl); remoteTokenServices.setClientId(clientId); remoteTokenServices.setClientSecret(clientSecret); remoteTokenServices.setAccessTokenConverter(accessTokenConverter()); return remoteTokenServices; }
有了这个配置,我得到了
{
"error": "access_denied",
"error_description": "Invalid token does not contain resource id
(xxxxx)"
}
为了解决这个问题,我不得不添加
private String resourceIds= "xxxxx". !! maked sure that this resourceids is store in oauth_client_details for the clientid I used to get the token
@Override
public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
resources.resourceId(resourceIds).tokenStore(tokenStore());
}
我在使用 spring 实现 oauth2.0 时遇到了同样的问题,这是我发现的关于 resourceid 的内容。
Spring Security OAuth2架构分为Authorization Server和Resource Server资源服务器。我们可以为每个 Resource Server(一个微服务实例)设置一个 ResourceID。 Authorization Server授权客户端时,可以设置客户端可以访问哪些Resource Server资源服务。
在授权服务器中为客户端配置ResourceID的目的是限制客户端可以访问的资源服务。
参考下面link设置ResourceID, https://www.fatalerrors.org/a/resource-of-spring-security-oauth2_-id-configuration-and-verification.html