OAuth2服务的提供端,包括两部分:

比如创建两个服务,uua服务用来做授权服务,order服务用来做资源服务。
Spring Security Oauth核心依赖:
org.springframework.security.oauth spring-security-oauth2 2.4.1 用 @EnableAuthorizationServer 注解并继承AuthorizationServerConfigurerAdapter来配置OAuth2.0 授权服务器。
或者直接去实现AuthorizationServerConfigurer接口都一样
@Configuration @EnableAuthorizationServer public class AuthorizationServer extends AuthorizationServerConfigurerAdapter { //略... } 
授权服务器中,需要配置以下三点:
ClientDetailsServiceConfigurer:用来配置客户端详情服务,看支持哪些客户端来请求
AuthorizationServerEndpointsConfigurer:解决两点:客户端来申请令牌了,申请的地址是什么(令牌端点)以及令牌怎么发放
AuthorizationServerSecurityConfigurer:配置令牌端点的安全约束,哪些url开放,哪些需要鉴权
通过ClientDetailsServiceConfigurer来配置客户端详情。而一个ClientDetails对象则是表示一个客户端的详情,包括客户端的ID、密码、授权范围、授权类型等。相关属性:
配置客户端详情可以通过内存和数据库的方式:
方式一:
客户端详情ClientDetails的查询要通过ClientDetailsService,可以直接用框架的JdbcClientDetailsService。也可自己实现ClientDetailsService接口和ClientRegistrationService接口的类,用于加载和增删改客户端详情信息。然后如下设置客户端详情服务
@Override public void configure(ClientDetailsServiceConfigurer clients) throws Exception { clients.withClientDetails(clientDetailsService) //... JdbcClientDetailsService相关源码:

方式二:
在内存中配置客户端详情服务,硬编码或者使用配置文件+@Value读取实现写活。如下:
/** * Oauth2.0客户端角色的信息来源:内存、数据库 * 这里用内存做测试 */ @Override public void configure(ClientDetailsServiceConfigurer clientDetailsServiceConfigurer) throws Exception { clientDetailsServiceConfigurer.inMemory() //使用内存 .withClient("c1") //client_id .secret(new BCryptPasswordEncoder().encode("123321")) //客户端密钥 .resourceIds("res1","res2") //资源列表,一个标识,后面配置资源服务会用到 .authorizedGrantTypes("authorization_code", "password", "client_credentials", "implicit", "refresh_token") //支持的授权模式,这里即四种都支持 .scopes("all") //允许授权的范围,一个标识 .autoApprove(false) //不自动授权,即跳转到授权页面,让用户授权 .redirectUris("http://your_url"); //验证回调地址,授权码通过302重定向方法,这里要验证回调地址是否被恶意篡改 //后面继续链式调用and方法可以配置第二个客户端的信息 } 通过以上配置,Spring Security将会在内存中或者数据库中加载客户端详情,并在认证和授权过程中使用这些信息来验证和授权客户端的请求。
AuthorizationServerTokenServices接口定义了令牌操作方法:

其实现类是DefaultTokenServices:

该实现类聚合了TokenStore接口,做持久化令牌(令牌存储策略)。其实现类:

以下演示内存中的,先定义TokenStore:
@Configuration public class TokenConfig { //令牌存储策略 @Bean public TokenStore tokenStore() { //放内存 return new InMemoryTokenStore(); } } 定义AuthorizationServerTokenServices,使用其实现类DefaultTokenServices,这里设置token的相关配置:
//注入上面定义的令牌存储策略的Bean @Autowired private TokenStore tokenStore; //注入客户端详情服务(定义下这个Bean,是实现方式:JDBC、内存、自己实现这个接口) @Autowired private ClientDetailsService clientDetailsService; //token令牌管理 @Bean public AuthorizationServerTokenServices tokenServices() { DefaultTokenServices tokenServices = new DefaultTokenServices(); tokenServices.setClientDetailsService(clientDetailsService); //客户端信息服务,即向哪个客户端颁发令牌 tokenServices.setSupportRefreshToken(true); //支持产生刷新令牌 tokenServices.setTokenStore(tokenStore); //令牌的存储策略 tokenServices.setAccessTokenValiditySeconds(7200); //令牌默认有效期2小时 tokenServices.setRefreshTokenValiditySeconds(259200); //refresh_token默认有效期三天 return tokenServices; } 定义好这令牌存储和令牌配置的两个Bean,下面重写第二个configure方法:
@Override public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception { //你的逻辑 } 这个方法AuthorizationServerEndpointsConfigurer类型的形参,可以配置授权服务器支持的授权类型:
示例:
/** * 授权信息保存策略 */ @Bean public ApprovalStore approvalStore(){ return new InMemoryApprovalStore(); } //AuthenticationManager对象在Oauth2认证服务中要使用,提取放到IOC容器中,实现WebSecurityConfigurerAdapter的安全配置类中配置 @Override @Bean public AuthenticationManager authenticationManagerBean() throws Exception { return super.authenticationManagerBean(); } //设置授权码模式下,授权码如何存储 @Bean(name = "jdbcAuthorizationCodeServices") public AuthorizationCodeServices authorizationCodeServices(){ return new InMemoryAuthorizationCodeServices(); } /** * 令牌端点访问和令牌服务(令牌怎么生成、怎么存储等) */ @Override public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception { endpoints.authenticationManager(authenticationManager) //设置认证管理器,密码模式需要 .authorizationCodeServices(authorizationCodeServices) //授权码模式需要 .approvalStore(approvalStore) .tokenServices(tokenServices()) //token管理服务 .allowedTokenEndpointRequestMethods(HttpMethod.POST); //允许Post方式访问 } 最后,配置授权端点的URL,框架默认URL为:
/oauth/authorize:授权端点 /oauth/token:令牌端点 /oauth/confirm_access:用户确认授权提交端点 /oauth/error:授权服务错误信息端点 /oauth/check_token:用于资源服务访问的令牌解析端点 /oauth/token_key:提供公有密匙的端点,如果你使用JWT令牌的话 AuthorizationServerEndpointsConfigurer的pathMapping方法可以把这些默认的URL替换成自己定义的URL,形参1为默认链接,形参2为新的自定义的URL链接
在这里配置框架提供的端点(url),哪些是可以对外公开的,比如下面即check/token接口对外公开
/** * token令牌端点访问的安全策略 * (不是所有人都可以来访问框架提供的这些令牌端点的) */ @Override public void configure(AuthorizationServerSecurityConfigurer authorizationServerSecurityConfigurer) throws Exception { authorizationServerSecurityConfigurer.tokenKeyAccess("permitAll()") //oauth/token_key这个端点(url)是公开的,不用登录可调 .checkTokenAccess("permitAll()") // oauth/check_token这个端点是公开的 .allowFormAuthenticationForClients(); //允许客户端表单认证,申请令牌 } Spring Security Oauth核心依赖:
org.springframework.security.oauth spring-security-oauth2 2.4.1 在资源服务做token校验,合法且权限匹配,则返回数据资源。配置方式:
用 @EnableResourceServer注解并继承 ResourceServerConfigurerAdapter(或实现ResourceServerConfigurer)来配置OAuth2.0 授权服务器。
@Configuration @EnableResourceServer @EnableGlobalMethodSecurity(securedEnabled = true) public class OAuthSourceConfig extends ResourceServerConfigurerAdapter { public static final String RESOURCE_ID = "res1"; @Resource ResourceServerTokenServices resourceServerTokenServices; @Bean public TokenStore tokenStore() { //放内存 return new InMemoryTokenStore(); } @Override public void configure(ResourceServerSecurityConfigurer resources) throws Exception { resources.resourceId(RESOURCE_ID) //资源id .tokenStore(tokenStore()) //告诉资源服务token在库里 .tokenServices(resourceServerTokenServices) .stateless(true); } @Override public void configure(HttpSecurity http) throws Exception { http.authorizeRequests() //这就是给客户端发token时的scope,这里会校验scope标识 .antMatchers("/**").access("#oauth2.hasAnyScope('all')") .and() .csrf().disable() .sessionManagement() .sessionCreationPolicy(SessionCreationPolicy.STATELESS); } } 通过ResourceServerSecurityConfigurer对象配置:
关于ResourceServerTokenServices,其用来验证token。如何授权服务和资源服务在一个应用上,可用DefaultTokenServices,使用/oauth/check_token这个端点去校验令牌。反之需要使用远程token服务RemoteTokenServices,指定授权服务器校验token的地址。以及自己的密钥和客户端ID:
@Configuration public class BeanConfig { @Bean public ResourceServerTokenServices tokenServices() { RemoteTokenServices services = new RemoteTokenServices(); services.setCheckTokenEndpointUrl("http://localhost:9009/oauth/check_token"); services.setClientId("c1"); services.setClientSecret("123"); return services; } }