上一篇:Spring Security + OAuth2(2. 环境搭建)
下一篇:Spring Security + OAuth2(4. OAuth 的四种模式)
@EnableAuthorizationServer
注解并继承AuthorizationServerConfigurerAdapter
来配置OAuth2.0 授权 服务器。简单说明部分(完整代码在下面):
在Config包下创建AuthorizationServer,并且需要继承 AuthorizationServerConfigurerAdapter
@Configuration
@EnableAuthorizationServer
public class AuthorizationServer extends AuthorizationServerConfigurerAdapter {
public AuthorizationServerConfigurerAdapter() {}
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {}
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {}
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {}
}
继承后,需要实现三个方法,上面也体现出来了,分别是
ClientDetailsServiceConfigurer
:用来配置客户端详情服务(ClientDetailsService),客户端详情信息在 这里进行初始化,你能够把客户端详情信息写死在这里或者是通过数据库来存储调取详情信息。
该方法也就是配置支持哪些客户端来请求。AuthorizationServerEndpointsConfigurer
:用来配置令牌(token)的访问端点(来申请令牌的 URL)和令牌服务(token services)(令牌的生成发放规则)。AuthorizationServerSecurityConfigurer
:用来配置令牌端点的安全约束
//客户端详情服务
@Override
public void configure(ClientDetailsServiceConfigurer clients)
throws Exception {
/*clients.withClientDetails(clientDetailsService);*/
clients.inMemory()// 使用in-memory存储
.withClient("c1")// client_id
.secret(new BCryptPasswordEncoder().encode("secret"))//客户端密钥
.resourceIds("res1")//资源列表
.authorizedGrantTypes("authorization_code", "password","client_credentials","implicit","refresh_token")// 该client允许的授权类型authorization_code,password,refresh_token,implicit,client_credentials
.scopes("all")// 允许的授权范围
.autoApprove(false)//false跳转到授权页面
//加上验证回调地址
.redirectUris("http://www.baidu.com")
;
}
简单说明:
ClientDetailsServiceConfigurer 能够使用内存或者JDBC来实现客户端详情服务(ClientDetailsService)
ClientDetailsService负责查找ClientDetails,而ClientDetails有几个重要的属性如下列表:
- clientId:(必须的)用来标识客户的Id。
- secret:(需要值得信任的客户端)客户端的安全码 / 密钥,如果有的话。
- scope:用来限制客户端的访问范围,如果为空(默认)的话,那么客户端拥有全部的访问范围。
- authorizedGrantTypes:此客户端可以使用的授权类型,默认为空。
- authorities:此客户端可以使用的权限(基于Spring Security authorities)。
客户端详情(Client Details)能够在应用程序运行的时候进行更新,可以通过访问底层的存储服务(例如将客户 端详情存储在一个关系数据库的表中,就可以使用 JdbcClientDetailsService)或者通过自己实现 ClientRegistrationService接口(同时你也可以实现 ClientDetailsService 接口)来进行管理
- InMemoryTokenStore:使用内存的方式
- JdbcTokenStore:使用数据库的方式
- JwtTokenStore:使用 JWT 的方式(后面再说)
定义TokenConfig
在config包下定义 TokenConfig ,暂时先使用InMemoryTokenStore,生成一个普通的令牌。
@Configuration
public class TokenConfig {
@Bean
public TokenStore tokenStore() {
return new InMemoryTokenStore();
}
}
定义AuthorizationServerTokenServices
在 AuthorizationServer 中定义AuthorizationServerTokenServices
@Autowired
private TokenStore tokenStore;
@Autowired
private ClientDetailsService clientDetailsService;
@Bean
public AuthorizationServerTokenServices tokenService() {
DefaultTokenServices service=new DefaultTokenServices();
service.setClientDetailsService(clientDetailsService);//客户端详情服务
service.setSupportRefreshToken(true);//支持刷新令牌
service.setTokenStore(tokenStore);//令牌存储策略
service.setAccessTokenValiditySeconds(7200); // 令牌默认有效期2小时
service.setRefreshTokenValiditySeconds(259200); // 刷新令牌默认有效期3天
return service;
}
authenticationManager
:认证管理器,当你选择了资源所有者密码(password)授权类型的时候,请设置 这个属性注入一个 AuthenticationManager 对象。userDetailsService
:如果你设置了这个属性的话,那说明你有一个自己的 UserDetailsService 接口的实现, 或者你可以把这个东西设置到全局域上面去(例如 GlobalAuthenticationManagerConfigurer 这个配置对 象),当你设置了这个之后,那么 “refresh_token” 即刷新令牌授权类型模式的流程中就会包含一个检查,用 来确保这个账号是否仍然有效,假如说你禁用了这个账户的话。authorizationCodeServices
:这个属性是用来设置授权码服务的(即 AuthorizationCodeServices 的实例对 象),主要用于 “authorization_code” 授权码类型模式。implicitGrantService
:这个属性用于设置隐式授权模式,用来管理隐式授权模式的状态。tokenGranter
:当你设置了这个东西(即 TokenGranter 接口实现),那么授权将会交由你来完全掌控,并 且会忽略掉上面的这几个属性,这个属性一般是用作拓展用途的,即标准的四种授权模式已经满足不了你的 需求的时候,才会考虑使用这个
在 AuthorizationServer 配置令牌访问端点
@Autowired
private AuthorizationCodeServices authorizationCodeServices;
@Autowired
private AuthenticationManager authenticationManager;
//设置授权码模式的授权码如何存取,暂时采用内存方式
@Bean
public AuthorizationCodeServices authorizationCodeServices() {
return new InMemoryAuthorizationCodeServices();
}
// 令牌访问端点的配置
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
endpoints
.authenticationManager(authenticationManager)//认证管理器
.authorizationCodeServices(authorizationCodeServices)//授权码服务
.tokenServices(tokenService())//令牌管理服务
.allowedTokenEndpointRequestMethods(HttpMethod.POST);
}
AuthorizationServerSecurityConfigurer
:用来配置令牌端点(Token Endpoint)的安全约束
在 AuthorizationServer 中配置如下
@Override
public void configure(AuthorizationServerSecurityConfigurer security){
security
.tokenKeyAccess("permitAll()") //oauth/token_key是公开
.checkTokenAccess("permitAll()") //oauth/check_token公开
.allowFormAuthenticationForClients() //表单认证(申请令牌)
;
}
配置授权端点的URL(Endpoint URLs):
AuthorizationServerEndpointsConfigurer 这个配置对象有一个叫做 pathMapping() 的方法用来配置端点URL链接,它有两个参数:
- 第一个参数:String 类型的,这个端点URL的默认链接。
- 第二个参数:String 类型的,你要进行替代的URL链接。
以上的参数都将以 “/” 字符为开始的字符串,框架的默认URL链接如下列表,就是上述的第一个参数:
- /oauth/authorize:授权端点。
- /oauth/token:令牌端点。
- /oauth/confirm_access:用户确认授权提交端点。
- /oauth/error:授权服务错误信息端点。
- /oauth/check_token:用于资源服务访问的令牌解析端点。
- /oauth/token_key:提供公有密匙的端点,如果你使用JWT令牌的话。
需要注意的是授权端点这个URL应该被Spring Security保护起来只供授权用户访问
在 Config 包下进行编写
@Configuration
@EnableGlobalMethodSecurity(securedEnabled = true,prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
//认证管理器
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
//密码编码器
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
//安全拦截机制(最重要)
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests()
.antMatchers("/r/r1").hasAnyAuthority("p1")
.antMatchers("/login*").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
;
}
}
@Configuration
@EnableAuthorizationServer
public class AuthorizationServer extends AuthorizationServerConfigurerAdapter {
@Autowired
private TokenStore tokenStore;
@Autowired
private ClientDetailsService clientDetailsService;
@Autowired
private AuthorizationCodeServices authorizationCodeServices;
@Autowired
private AuthenticationManager authenticationManager;
//客户端详情服务
@Override
public void configure(ClientDetailsServiceConfigurer clients)
throws Exception {
/*clients.withClientDetails(clientDetailsService);*/
clients.inMemory()// 使用in-memory存储
.withClient("c1")// client_id
.secret(new BCryptPasswordEncoder().encode("secret"))//客户端密钥
.resourceIds("res1")//资源列表
.authorizedGrantTypes("authorization_code", "password","client_credentials","implicit","refresh_token")// 该client允许的授权类型authorization_code,password,refresh_token,implicit,client_credentials
.scopes("all")// 允许的授权范围
.autoApprove(false)//false跳转到授权页面
//加上验证回调地址
.redirectUris("http://www.baidu.com");
}
//令牌管理服务
@Bean
public AuthorizationServerTokenServices tokenService() {
DefaultTokenServices service=new DefaultTokenServices();
service.setClientDetailsService(clientDetailsService);//客户端详情服务
service.setSupportRefreshToken(true);//支持刷新令牌
service.setTokenStore(tokenStore);//令牌存储策略
service.setAccessTokenValiditySeconds(7200); // 令牌默认有效期2小时
service.setRefreshTokenValiditySeconds(259200); // 刷新令牌默认有效期3天
return service;
}
//设置授权码模式的授权码如何存取,暂时采用内存方式
@Bean
public AuthorizationCodeServices authorizationCodeServices() {
return new InMemoryAuthorizationCodeServices();
}
// 令牌访问端点的配置
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
endpoints
.authenticationManager(authenticationManager)//认证管理器
.authorizationCodeServices(authorizationCodeServices)//授权码服务
.tokenServices(tokenService())//令牌管理服务
.allowedTokenEndpointRequestMethods(HttpMethod.POST);
}
@Override
public void configure(AuthorizationServerSecurityConfigurer security){
security
.tokenKeyAccess("permitAll()") //oauth/token_key是公开
.checkTokenAccess("permitAll()") //oauth/check_token公开
.allowFormAuthenticationForClients() //表单认证(申请令牌)
;
}
}