续·前一篇《OAuth 2.0》html
在OAuth 2.0中,provider角色事实上是把受权服务和资源服务分开,有时候它们也可能在同一个应用中,用Spring Security OAuth你能够选择把它们分红两个应用,固然多个资源服务能够共享同一个受权服务。java
获取token的请求由Spring MVC的控制端点处理,访问受保护的资源由标准的Spring Security请求过滤器处理。git
(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. )github
为了实现OAuth 2.0受权服务器,在Spring Security的过滤器链中须要有如下端点:web
在OAuth 2.0的资源服务器中须要实现下列过滤器:spring
对于全部的OAuth 2.0 provider特性,最简单的配置是用Spring OAuth @Configuration适配器。sql
只要你配置了受权服务器,那么你应该考虑客户端用于获取access token的受权类型(例如,受权码,用户凭证,刷新token)。数据库
服务器的配置是用来提供client detail服务和token服务的,而且能够启用或者禁用全局的某些机制。后端
每一个客户端能够配置不一样的权限api
@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