我只是应用Spring Boot和Spring Cloud来构建一个微服务系统。我也将Spring Oauth应用于它。老实说,一切都很完美。 Spring在这方面做得很好。 在这个系统中,我有一个微服务项目完成OAuth服务器的工作,使用JDBC数据源,我使用基于Permission for UserDetails权限(1个用户有几个权限)。有几个微服务项目负责资源服务器的工作(使用Jersey公开Rest api),访问安全性基于OAuth承载令牌的认证权限。
资源服务器OAuth配置类就是这样的
@Configuration
@EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
@Override
public void configure(HttpSecurity http) throws Exception {
http.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
http.csrf().disable();
http.authorizeRequests()
.antMatchers("/restservice/object/list")
.hasAuthority("PERMISSION_VIEW_OBJECT_LIST");
// ...
}
@Override
public void configure(ResourceServerSecurityConfigurer resources)
throws Exception {
resources.resourceId("abc-resource-id")
.tokenStore(new JdbcTokenStore(dataSource()));
}
@Bean
@ConfigurationProperties(prefix = "oauth2.datasource")
public DataSource dataSource() {
return DataSourceBuilder.create().build();
}
}
一切都很棒!但我遇到了两个问题:
如果我将新的微服务项目添加为新的resourceId,并且我将resourceId值附加到OAuth客户端的表OAUTH_CLIENT_DETAILS中的RESOURCE_IDS,则对新资源服务的Rest API的所有请求都会返回类似这样的错误 {"错误":" access_denied"," error_description":"无效的令牌不包含资源ID(xyz-resource-id)" } 即使用户注销并重新登录以获取新的访问令牌,也会发生这种情况。它只适用于我在数据库中删除Access令牌和刷新令牌int表OAUTH_ACCESS_TOKEN和OAUTH_REFRESH_TOKEN的记录。
如果在运行时更改了用户的权限,则不会重新加载身份验证的权限,我看到表OAUTH_ACCESS_TOKEN中的访问令牌的AUTHENTICATION值在更改权限之前仍包含旧权限。在这种情况下,用户必须注销并重新登录才能获得具有更改权限的新访问令牌。
那么,有没有办法解决这两个问题。 我使用的是Spring Cloud Brixton.SR4和Spring Boot 1.3.5.RELEASE。
答案 0 :(得分:2)
如果您使用的是默认的Spring JdbcTokenStore,那么当用户首次验证并检索其令牌时,用户身份验证将被序列化并与访问/刷新令牌一起存储。
每次使用令牌进行身份验证时,都会加载此存储的身份验证,这就是为什么更改用户权限或添加额外资源不会反映在用户权限中的原因。
为了添加一些检查,您可以扩展DefaultTokenServices并覆盖loadAuthentication(String accessTokenValue)方法,以便在从令牌存储加载用户身份验证后执行您自己的检查。
这可能不是理想的做法,但这是迄今为止我们发现的唯一方法。
要覆盖DefaultTokenServices,请将以下bean方法添加到AuthorizationServerConfigurerAdapter配置类:
class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
@Bean
public AuthorizationServerTokenServices authorizationServerTokenServices() throws Exception {
// Where YourTokenServices extends DefaultTokenServices
YourTokenServices tokenServices = new YourTokenServices();
tokenServices.setTokenStore(tokenStore);
tokenServices.setClientDetailsService(clientDetailsService);
return tokenServices;
}
}
答案 1 :(得分:0)
我通过这种方式解决了重装问题。
@Bean
public ClientDetailsService jdbcClientDetailsService() {
return new JdbcClientDetailsService(dataSource);
}