微服务和 Spring Security OAuth2
Posted
技术标签:
【中文标题】微服务和 Spring Security OAuth2【英文标题】:Microservices and Spring Security OAuth2 【发布时间】:2014-12-27 11:34:21 【问题描述】:我已经在另一个项目中运行了 OAuth2 授权服务器。现在我需要使用 OAuth2 保护几个简单的 spring-boot 休息服务器。但我发现 Spring documentation 在分离授权和资源服务器方面确实非常有限。
我还发现了几个问题,the answer 一直是“只要它们共享相同的 tokenStore 数据源,它们就可以是不同的盒子”。这真的是真的吗?这怎么可能适用于微服务?每个 REST 服务都需要实现自己的 OAuth 授权服务器,这似乎是一件非常奇怪的事情。
那么,如何为引用远程 oauth 授权服务器(甚至可能不是用 Spring 编写)的 spring-boot rest-endpoints 设置 Oauth2.0 安全性?
有一个叫做RemoteTokenServices 的东西看起来很有希望,但它根本没有真正记录在案。
【问题讨论】:
【参考方案1】:RemoteTokenService
的工作示例可以在 here 找到。
更多关于check_token
api的详细信息,可以参考org.springframework.security.oauth2.provider.endpoint.CheckTokenEndpoint.java
在资源服务器端,OAuth2AuthenticationProcessingFilter
通过调用 OAuth2AuthenticationManager.authenticate()
方法验证 OAuth2 令牌,该方法调用 RemoteTokenServices.loadAuthentication()
以验证来自 Auth 服务器的令牌。
【讨论】:
【参考方案2】:在配置您的 auh 服务器时::
在ClientDetailsServiceConfigurer
中为资源服务器创建一个新的clientDetails。将用于配置RemoteTokenService
。
在资源服务器中配置 Spring Security OAuth2:
创建一个使用@EnableWebSecurity
、@Configuration
注释并扩展WebSecurityConfigurerAdapter
的类。
@Configuration
@EnableWebSecurity
protected static class ResourceConfiguration extends WebSecurityConfigurerAdapter
// methods
创建一个带有@Bean 注解的方法,该方法将返回TokenService
的实例,该实例将用于创建AuthenticationManager
。
在这个方法中创建一个RemoteTokenService
的实例并设置clientId、client_secret、checkTokenEndpointUrl和DefaultAccessTokenConverterWithClientRoles
(这个类是我们在验证accessToken时获取client_authority的实现在 OAuth2 服务器中。)
@Bean
public ResourceServerTokenServices tokenService()
RemoteTokenServices tokenServices = new RemoteTokenServices();
tokenServices.setClientId("resource_id");
tokenServices.setClientSecret("resource_secret");
tokenServices.setCheckTokenEndpointUrl("http://<server-url>: <port>/oauth/check_token");
return tokenServices;
覆盖authenticationManagerBean()
方法并使用@Bean
对其进行注释,并返回一个OAuth2AuthenticationManager
的实例并注入TokenService
。
@Override
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception
OAuth2AuthenticationManager authenticationManager = new OAuth2AuthenticationManager();
authenticationManager.setTokenServices(tokenService());
return authenticationManager;
创建一个用@EnableResourceServer
、@Configuration
注解的类并扩展ResourceServerConfigurerAdapter
。
@Configuration
@EnableResourceServer
protected static class ResourceServerConfig extends ResourceServerConfigurerAdapter
// Mehotds
覆盖超类的配置方法来配置资源服务器。 不同的配置器来配置资源服务器。
ResourceServerSecurityConfigurer:配置Resource_id。
HttpSecurity:这将配置安全过滤器,告诉它用户需要对受保护的 URL (API) 进行身份验证。
@Override
public void configure(ResourceServerSecurityConfigurer resources) throws Exception
resources.resourceId("resource_id");
@Override
public void configure(HttpSecurity http) throws Exception
// @formatter:off
http
.authorizeRequests()
.antMatchers("/**").authenticated()
.and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
// @formatter:on
.antMatcher("/**").authenticated()
这一行将保护资源服务器的每个 api url。
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
不会创建会话。
PS:: 如果有什么不对的,请告诉我。
【讨论】:
此设置是否在真实应用中测试过?其中大部分看起来与我在项目中所做的相同。但是,我在无状态配置方面遇到了麻烦。登录和授权页面之间丢失了一些东西。我认为 OAuth2 实现不支持无状态设置,因为 RequestCache 接口的唯一实现需要一个 http 会话来存储请求信息(HttpSessionRequestCache)。无状态策略会将此请求数据存储回响应中(可能在 cookie 中),因此任何其他副本都可以继续授权【参考方案3】:如果资源服务器有某种方法可以验证访问令牌是否真实(由授权服务器颁发)以及某种解码方法(可能需要例如,了解它授予的范围)。 OAuth2 规范没有说明如何实现这一点。
如果资源与授权服务器在同一个进程中,那么共享数据是一个简单的选择。否则,它需要某种方式来翻译令牌。如果令牌只是一个不透明的随机字节串,那么显然它必须用它来交换真实的信息。这就是RemoteTokenServices
所做的。授权服务器公开一个/check_token
端点以允许对令牌进行解码。
另一种方法是对令牌中的信息进行实际编码,并让授权服务器对其进行数字签名。然后资源服务器可以解码和验证令牌本身,只要它理解格式。
我建议您查看 Cloudfoundry UAA,它提供了一个开箱即用的授权服务器,该服务器使用签名的 JWT 令牌实现(它还公开了 /check_token
端点)。 Tokens overview 和 API docs 可能是一个很好的起点。
【讨论】:
tokenServices.setCheckTokenEndpointUrl("http://<server-url>: <port>/oauth/check_token");
有没有办法避免硬编码的网址?我想直接调用任何一个身份验证服务器实例(从注册表服务器获取运行时 url)或从 redis 检查令牌。 (在 auth 中使用 redis 令牌存储)这有可能吗?以上是关于微服务和 Spring Security OAuth2的主要内容,如果未能解决你的问题,请参考以下文章