OAuth 2.0 Provider 实现
在OAuth 2.0中,provider角色事实上是把授权服务和资源服务分开,有时候它们也可能在同一个应用中,用Spring Security OAuth你可以选择把它们分成两个应用,当然多个资源服务可以共享同一个授权服务。
获取token的请求由Spring MVC的控制端点处理,访问受保护的资源由标准的Spring Security请求过滤器处理。
(The requests for the tokens are handled by Spring MVC controller endpoints, and access to protected resources is handled by standard Spring Security request filters. )
为了实现OAuth 2.0授权服务器,在Spring Security的过滤器链中需要有以下端点:
在OAuth 2.0的资源服务器中需要实现下列过滤器:
对于所有的OAuth 2.0 provider特性,最简单的配置是用Spring OAuth @Configuration适配器。
只要你配置了授权服务器,那么你应该考虑客户端用于获取access token的授权类型(例如,授权码,用户凭证,刷新token)。
服务器的配置是用来提供client detail服务和token服务的,并且可以启用或者禁用全局的某些机制。
每个客户端可以配置不同的权限
@EnableAuthorizationServer注解被用来配置授权服务器,也可以和实现了AuthorizationServerConfigurer接口的任意被标记为@Bean的Bean一起来对授权服务器进行配置。
下列特性被委托给AuthorizationServerConfigurer:
一件重要的事情是,provider配置了将授权码给OAuth客户端的方式(PS:在授权码类型授权过程中)
OAuth客户端通过将end-user(最终用户)导向授权页,用户可用在此输入他的凭证。之后,授权服务器携带授权码通过重定向的方式将授权码返回给客户端。
The ClientDetailsServiceConfigurer (a callback from your AuthorizationServerConfigurer) can be used to define an in-memory or JDBC implementation of the client details service.
ClientDetailsServiceConfigurer可用使用client details service的两种实现中的任意一种:in-memory 或者 JDBC
客户端重要的属性是:
客户端details可以在应用运行时被更新,通过直接访问存储(例如:如果用JdbcClientDetailsService的话可以实时改变数据库表中的数据)或者通过实现ClientDetailsManager接口(它们也都实现了ClientDetailsService接口)。
NOTE: the schema for the JDBC service is not packaged with the library (because there are too many variations you might like to use in practice), but there is an example you can start from in the test code in github.
注意:用于JDBC服务的数据库schema并没有打包到library中(因为你再实际使用的时候可能有诸多差异),但是这里有一个例子你可以参考一下。
https://github.com/spring-projects/spring-security-oauth/blob/master/spring-security-oauth2/src/test/resources/schema.sql
1 -- used in tests that use HSQL 2 create table oauth_client_details ( 3 client_id VARCHAR(256) PRIMARY KEY, 4 resource_ids VARCHAR(256), 5 client_secret VARCHAR(256), 6 scope VARCHAR(256), 7 authorized_grant_types VARCHAR(256), 8 web_server_redirect_uri VARCHAR(256), 9 authorities VARCHAR(256), 10 access_token_validity INTEGER, 11 refresh_token_validity INTEGER, 12 additional_information VARCHAR(4096), 13 autoapprove VARCHAR(256) 14 ); 15 16 create table oauth_client_token ( 17 token_id VARCHAR(256), 18 token LONGVARBINARY, 19 authentication_id VARCHAR(256) PRIMARY KEY, 20 user_name VARCHAR(256), 21 client_id VARCHAR(256) 22 ); 23 24 create table oauth_access_token ( 25 token_id VARCHAR(256), 26 token LONGVARBINARY, 27 authentication_id VARCHAR(256) PRIMARY KEY, 28 user_name VARCHAR(256), 29 client_id VARCHAR(256), 30 authentication LONGVARBINARY, 31 refresh_token VARCHAR(256) 32 ); 33 34 create table oauth_refresh_token ( 35 token_id VARCHAR(256), 36 token LONGVARBINARY, 37 authentication LONGVARBINARY 38 ); 39 40 create table oauth_code ( 41 code VARCHAR(256), authentication LONGVARBINARY 42 ); 43 44 create table oauth_approvals ( 45 userId VARCHAR(256), 46 clientId VARCHAR(256), 47 scope VARCHAR(256), 48 status VARCHAR(10), 49 expiresAt TIMESTAMP, 50 lastModifiedAt TIMESTAMP 51 ); 52 53 54 -- customized oauth_client_details table 55 create table ClientDetails ( 56 appId VARCHAR(256) PRIMARY KEY, 57 resourceIds VARCHAR(256), 58 appSecret VARCHAR(256), 59 scope VARCHAR(256), 60 grantTypes VARCHAR(256), 61 redirectUrl VARCHAR(256), 62 authorities VARCHAR(256), 63 access_token_validity INTEGER, 64 refresh_token_validity INTEGER, 65 additionalInformation VARCHAR(4096), 66 autoApproveScopes VARCHAR(256) 67 );
AuthorizationServerTokenServices定义了管理OAuth 2.0 Token所必须的操作。请注意:
当你实现了AuthorizationServerTokenServices接口,你可能考虑用DefaultTokenServices。有许多内置的插件化的策略可以用来改变access token的格式和存储。
默认情况下,用随机值来生成token,并且用TokenService来处理所有(除了token持久化以外)事情。默认的存储是in-memory实现,但是有其它的实现可以使用。
注意:对于JDBC的schema没有打包到library中,但是这儿有一个例子你可以参考一下test code in github。确保用@EnableTransactionManagement来防止多个客户端在同一行创建token。注意,示例中的schema都有明确地主键声明,在并发环境中这是必须的。
为了使用JWT Tokens,你需要在你的授权服务器中有一个JwtTokenStore。资源服务器也需要解码这个token,所以JwtTokenStore有一个依赖JwtAccessTokenConverter,相同的实现需要被包含在授权服务器和资源服务器中。也就是说,授权服务器和资源服务器中都需要JwtTokenStore实现。默认情况下,token是被签名的,而且资源服务器必须能够校验这个签名,因此需要有相同的对称key,或者需要公钥来匹配授权服务器上的私钥。公钥被授权服务器暴露在/oauth/token_key端点,默认情况下这个端点的访问规则是”denyAll()”。你可以用标准的SpEL表达式(例如:permitAll())到AuthorizationServerSecurityConfigurer来开放它。
为了使用JwtTokenStore,在classpath下需要有”spring-security-jwt”
授权类型通过AuthorizationEndpoint来支持。默认情况下,除了password以外,所有授权类型都支持。下面是授权类型的一些属性:
AuthorizationServerEndpointsConfigurer有一个pathMapping()方法。它有两个参数:
下面是框架提供的URL路径:
授权端点/oauth/authorize应该被保护起来,以至于它只能被认证过的用户访问。下面是一个例子,用标准的Spring Security WebSecurityConfigurer :
@Override protected void configure(HttpSecurity http) throws Exception { http .authorizeRequests().antMatchers("/login").permitAll().and() // default protection for all resources (including /oauth/authorize) .authorizeRequests() .anyRequest().hasRole("USER") // ... more configuration, e.g. for form login }
注意:如果您的授权服务器同时也是一个资源服务器的话,那么就有另一个具有较低优先级的安全过滤器链来控制API资源。通过访问令牌来保护这些请求,你需要它们的路径不能与主用户过滤器链中的那些相匹配,所以请确保包含一个请求matcher,它只挑选出上面的WebSecurityConfigurer中的非api资源。
授权服务器的大多数端点主要都是被机器使用的,但是有两个资源是需要UI,它们分别是/oauth/confirm_access和HTML响应/oauth/error。框架为它们提供的实现是空白页,真实的情况是大多数授权服务器可能想要提供它们自己的实现来控制样式和内容。所以,你需要做的事情就是提供一个Spring MVC 被标注了@RequestMappings注解的Controller来映射这些端点,并且框架将用一个低的优先级来发放请求。在默认的/oauth/confirm_access你期望一个AuthorizationRequest绑定到session。你可以抓取请求的所有数据并按照自己喜欢的方式渲染它们,然后用户需要做的就是向/oauth/authorize发送关于批准或拒绝授予的信息。默认的UserApprovalHandler取决于是否你再AuthorizationServerEndpointsConfigurer中提供了一个ApprovalStore。标准的审批处理器如下:
纯HTTP对于测试来说是可以的,但是在生成中授权服务器应该使用SSL。你可以在一个安全的容器或代理后面运行应用程序,如果你正确地设置代理和容器(这与OAuth2无关),那么它应该可以正常工作。对于/authorize端点你需要把它当作正常的应用安全的一部分来做,对于/token端点在AuthorizationServerEndpointsConfigurer中有一个标记可以设置,通过用sslOnly()方法。
授权服务器用标准的Spring MVC特性来进行错误处理。
你可以提供自己的实现,通过添加@Controller并且带上@RequestMapping(“/oauth/error”)
有时候,为了限制token的scope,不仅仅要根据指定的客户端的范围,也要根据用户自己的权限来进行限制。如果你在你的AuthorizationEndpoint用DefaultOAuth2RequestFactory,你可以设置checkUserScopes=true来限制匹配的用户角色的允许范围。AuthorizationServerEndpointsConfigurer允许你注入一个自定义的OAuth2RequestFactory
一个资源服务器(可能与授权服务器是相同的应用,也可能与授权服务器是分开的应用)通过OAuth2 Token服务受保护的资源。
Spring OAuth 提供一个Spring Security认证过滤器来实现这个保护。你可以
你可以在一个@Configuration类上用@EnableResourceServer来切换它,并且用ResourceServerConfigurer配置它。下列特性可以被配置:
@EnableResourceServer注释将自动添加一个OAuth2AuthenticationProcessingFilter类型的过滤器到Spring安全过滤器链中。
受保护的资源(或者叫远程资源)可以用OAuth2ProtectedResourceDetails类型的bean来定义。一个被保护的资源由下列属性:
不同的授权类型有不同的OAuth2ProtectedResourceDetails的具体实现(例如:ClientCredentialsResourceDetails是”client_credentials”类型的具体实现)
对于OAuth 2.0客户端配置,简化的配置用@EnableOAuth2Client。这个注解做两件事情:
AccessTokenRequest可以用在一个OAuth2RestTemplate中,就像下面这样:
@Autowired private OAuth2ClientContext oauth2Context; @Bean public OAuth2RestTemplate sparklrRestTemplate() { return new OAuth2RestTemplate(sparklr(), oauth2Context); }
建议用RestTemplate访问受保护的资源。
Spring Security为OAuth提供了一个扩展的RestTemplate只需要你提供一个OAuth2ProtectedResourceDetails的实例即可。为了使它和用户token(授权码方式授权)一起使用,你应该考虑用@EnableOAuth2Client配置。
一般来说,web应用程序不应该使用密码授予,因此如果您可以支持AuthorizationCodeResourceDetails,请避免使用ResourceOwnerPasswordResourceDetails。
为了和用户令牌(授权码)一起使用,你应该考虑用@EnableOAuth2Client配置。
客户端不需要持久化令牌,但是最好不要在每次重启客户端应用程序时都要求用户批准新的令牌授予。
ClientTokenServices接口定义了为特定用户保存OAuth 2.0令牌所需的操作。这是一个JDBC实现,但是如果您希望实现自己的服务,以便在持久数据库中存储访问令牌和相关的身份验证实例,则可以这样做。如果你想要使用这个特性,你需要为OAuth2RestTemplate提供一个经过特殊配置的TokenProvider。例如:
@Bean @Scope(value = "session", proxyMode = ScopedProxyMode.INTERFACES) public OAuth2RestOperations restTemplate() { OAuth2RestTemplate template = new OAuth2RestTemplate(resource(), new DefaultOAuth2ClientContext(accessTokenRequest)); AccessTokenProviderChain provider = new AccessTokenProviderChain(Arrays.asList(new AuthorizationCodeAccessTokenProvider())); provider.setClientTokenServices(clientTokenServices()); return template; }
https://projects.spring.io/spring-security-oauth/docs/oauth2.html
来源:https://www.cnblogs.com/cjsblog/p/9184173.html