微服务和 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的主要内容,如果未能解决你的问题,请参考以下文章
使用 Spring Security 保护 REST 微服务
如何使用 Spring Security 为微服务创建自定义安全过滤器
Spring starter security or spring cloud security 如何保护整个微服务架构?
具有密码授予类型的 WebClient 的 Spring Security OAuth 客户端不要求新令牌
微服务 Spring Cloud Gateway + Spring Security LDAP 作为 SSO + JWT - 请求/响应之间丢失令牌