一 引言
本文主要好介绍了SpringCloud+Security+Oauth2 的初步集成,项目源码地址oauth2.0集成案例,以下案例主要是核心源码的解释,案例源码请查看案例源码
二 项目结构说明
oauth-server
oauth认证中心
oauth-client
oauth客户端
oauth-nacos
注册中心和配置中心
oauth-common
公用组件
三 认证中心的搭建
Oauth2提供了AuthorizationServerConfigurerAdapter
适配器类来作为认证授权服务的配置,其中有三个方法源码如下:
public class AuthorizationServerConfigurerAdapter {
//客户端详情:配置客户端请求的参数
public void configure(ClientDetailsServiceConfigurer clients)...
//授权服务断点:配置授权码和令牌的管理/存储方式
public void configure(AuthorizationServerEndpointsConfigurer endpoints)...
//授权服务安全配置:配置哪些路径放行(检查token的路径要放行)
public void configure(AuthorizationServerSecurityConfigurer security) ...
}
配置详解:
ClientDetailsServiceConfigurer
:用来配置客户端详情服务
:如配置客户端id(client_id)资源id、客户端密钥(secrect)、授权方式、scope等,可以基于内存或jdbc。(可以理解为是对浏览器向授权服务器获取授权码或令牌时需要提交的参数配置
),如果你做过三方登录应该就能理解这些参数,其实就是对客户端的参数配置
,在客户端获取授权码或者获取Token的URL请求中就需要带上这些客户端参数AuthorizationServerEndpointsConfigurer
:配置令牌的访问端点url和令牌服务
,如配置如何管理授权码(内存或jdbc),如何管理令牌(存储方式,有效时间等等)AuthorizationServerSecurityConfigurer
: 用来配置令牌端点的安全约束
,如配置对获取授权码,检查token等某些路径进行放行
3.1 认证中心搭建
@Configuration
@EnableAuthorizationServer // 开启认证服务
public class AuthServerConfig extends AuthorizationServerConfigurerAdapter {
// 数据源
@Autowired
private DataSource dataSource;
@Autowired
private TokenStore tokenStore;
@Autowired
private AuthenticationManager authenticationManager;
// 客户端配置
@Bean
public ClientDetailsService customClientDetailsService(){
return new JdbcClientDetailsService(dataSource);
}
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
/**
* 必须将secret加密后存入数据库,否则报错:Encoded password does not look like BCrypt
*/
clients.withClientDetails(customClientDetailsService());
}
@Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer) {
oauthServer
//对应/oauth/token_key 公开,获取公钥需要访问该端点
.tokenKeyAccess("permitAll()")
//对应/oauth/check_token ,路径需要授权,校验Token需要请求该端点
.checkTokenAccess("isAuthenticated()")
//允许客户端进行表单身份验证,使用表单认证申请令牌
.allowFormAuthenticationForClients();
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.tokenStore(tokenStore);
endpoints.authenticationManager(authenticationManager);
DefaultTokenServices tokenServices = new DefaultTokenServices();
tokenServices.setTokenStore(endpoints.getTokenStore());
tokenServices.setSupportRefreshToken(true);
tokenServices.setClientDetailsService(endpoints.getClientDetailsService());
tokenServices.setTokenEnhancer(endpoints.getTokenEnhancer());
tokenServices.setAccessTokenValiditySeconds((int) TimeUnit.DAYS.toSeconds(30));
endpoints.tokenServices(tokenServices);
}
}
配置详解:
配置类上贴注解@EnableAuthorizationServer
开启授权服务配置,继承AuthorizationServerConfigurerAdapter
实现配置的增强配置
客户端详情配置
JdbcClientDetailsService
默认会去找数据库中的 名字为oauth_client_details
表中的数据作为客户端详情的配置,见 JdbcClientDetailsService类的源代码,所以我们需要在数据库执行以下sql创建表:并填充好数据
DROP TABLE IF EXISTS `oauth_client_details`;
CREATE TABLE `oauth_client_details` (
`client_id` varchar(48) NOT NULL,
`resource_ids` varchar(256) DEFAULT NULL,
`client_secret` varchar(256) DEFAULT NULL,
`scope` varchar(256) DEFAULT NULL,
`authorized_grant_types` varchar(256) DEFAULT NULL,
`web_server_redirect_uri` varchar(256) DEFAULT NULL,
`authorities` varchar(256) DEFAULT NULL,
`access_token_validity` int(11) DEFAULT NULL,
`refresh_token_validity` int(11) DEFAULT NULL,
`additional_information` varchar(4096) DEFAULT NULL,
`autoapprove` varchar(256) DEFAULT NULL,
PRIMARY KEY (`client_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
授权服务配置
主要是通过AuthorizationServerEndpointsConfigurer
配置授权码和令牌相关的服务 ,在上面的配置类基础上增加配置内容
AuthenticationManager
认证管理器“password”模式会用到认证管理器,它是在Security配置中定义的
TokenStore
: token存储方式该接口常用的实现有:InMemoryTokenStore
基于存储的token存储方案,JdbcTokenStore基于数据库的token存储方案,JwtToeknStore
基于JWT的存储方案,RedisTokenStore
基于Redis的存储方案,我上面的案例采用的是Redis的方式来实现
AuthorizationServerTokenServices
该接口用来配置授权服务器令牌,如配置是否支持Token,Token的存储方式(内 存,jdbc,),token加密,token过期等
令牌端点安全配置
AuthorizationServerSecurityConfigurer:用来配置令牌端点的安全策略
3.2 加载用户数据
在面的Security中我们已经介绍了UserDetailsService 在进行用户认证的时候回调用该接口获得用户信息,实现改接口,根据用户名校验当前用户是否存在
@Component
public class UserDetailServiceImpl implements UserDetailsService {
@Autowired
BCryptPasswordEncoder passwordEncoder;
@Autowired
private RemoteUserService remoteUserService;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
// 查询数据库 获得相应的用户
PtUser ptUser = remoteUserService.findOneByAccount(username);
if (ptUser==null){
throw new UsernameNotFoundException("用户名或密码错误");
}
// todo 查询相应的角色 这里不做演示
return new User(ptUser.getAccount(),ptUser.getPassword(), AuthorityUtils.NO_AUTHORITIES);
}
}
3.3 采用密码模式 获取token
http://localhost:9527/oauth/token?client_id=clientApp&client_secret=secretApp&grant_type=password&username=sys&password=123456
四 客户端搭建
4.1 客户端配置
通过@EnableResourceServer
开启客户端配置,继承ResourceServerConfigurerAdapter
开启对客户端的增强配置
@Configuration
@EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
@Autowired
private TokenStore tokenStore;
@Autowired
private ResourceServerTokenServices resourceServerTokenServices;
@Override
public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
resources.tokenStore(tokenStore);
resources.tokenServices(resourceServerTokenServices);
}
@Override
public void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/user/**").permitAll()// 放行用户相关的接口
.anyRequest().authenticated();// 其他接口需要鉴权
}
}
配置说明:
ResourceServerSecurityConfigurer
主要用于客户端关于oauth相关配置
- ResourceServerTokenServices 用于客户端token的校验,当用户携带token请求资源时,资源服务器会向认证中心发送请求校验token的正确性,并把用户信息加载到安全上下文中
- TokenStore 用于配置token的解析
HttpSecurity
主要是对SpringSecurity中的相关配置
4.2 yml配置token校验的相关配置
security:
oauth2:
client:
client-id: clientApp # oauth 分发的client-id
client-secret: secretApp # oauth 分发的client-secret
resource:
token-info-uri: http://localhost:9527/oauth/check_token # 认证中心token校验
4.3 测试
通过上面获得的token我们去访问资源服务器的相关资源
携带token请求成功
不携带token,请求失败
由此Spring Security+oauth2.0简单搭建由此集成了