前面我们已经把基本的授权服务器弄好了,并能根据四种方式获取到token了。今天就再讲讲具体的一些东西。
今天要做的事情如下
1,管理用户数据
2,修改原生返回token的内容(令牌增强器)
3,tokenStore(令牌持久化接口,令牌存储介质)
管理用户数据
比方我们前一篇文中的用户名和密码是使用spring security auth2.0 默认产生的,那如果使用我们的一套用户体系怎么弄呢?我们这里先看一下增加几个账号怎么加?加的方式其实很简单,本身原来中就提供了内存式的userdetailService,数据库式的jdbcdetailservice
替换auth2.0中跟用户操作有关的类UserDetailsService,JdbcUserDetailService,InMemoryUserDetailsManager等相关类。大家有空可以去看一下这一块的代码,根据你的设置采用不同的userDetailService,相关的类还有如下
然后有一个最重要的方法是loadUserByUserName方法,如果现有的一些UserDetailService还是无法满足你们系统的业务需求的,那你可以自己写一个类实现UserDetailService接口,重新loadUserByUserName就可以了,auth2.0内部会自动使用你这个类。
回到原点,我们先讲一下内存式加账号的方式。只需要在我们的AuthServerConfig类中加如下代码
@Bean
protected UserDetailsService userDetailsService(){
InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
manager.createUser(User.withUsername("user_1").password("123456").authorities("USER").build());
manager.createUser(User.withUsername("user_2").password("123456").authorities("USER").build());
return manager;
}
这样就可以了
数据库式的也只要在上面的代码改成如下
@Bean
protected UserDetailsService userDetailsService(){
JdbcUserDetailsManager manager = new JdbcUserDetailsManager();
return manager;
}
注意一下:这个数据库式的方式一定要满足它自己本身的数据库表设计,从源码中可以看出来
如果你自己要设计出符合自己系统的UserDetailService,就按照我上面的做法就可以了
2,讲下来我们怎么修改原生token的内容
这里我们只需要增加一个CustomTokenEnhancer实现TokenEnhancer重新enhance方法,这个方法就是修改原生token的方法
public class CustomTokenEnhancer implements TokenEnhancer {
@Override
public OAuth2AccessToken enhance(OAuth2AccessToken oAuth2AccessToken, OAuth2Authentication oAuth2Authentication) {
DefaultOAuth2AccessToken token = null;
if (oAuth2AccessToken instanceof DefaultOAuth2AccessToken) {
token = ((DefaultOAuth2AccessToken) oAuth2AccessToken);
//token.setValue(getNewToken()); //修改token的vakue值
String type = oAuth2AccessToken.getTokenType();
if ("authorization_code".equals(type)) {
//如果授权方式是code的方式,在兼容原先的基础上更改,增加一个过期时间
Map<String, Object> additionalInformation = new HashMap<String, Object>();
additionalInformation.put("refresh_exp", token.getExpiration());
token.setAdditionalInformation(additionalInformation);
}
}
return token;
}
}
然后在Oauth2ServerConfig中加如下代码
@Bean
public TokenEnhancer tokenEnhancer() {
return new CustomTokenEnhancer();
// return new TokenEnhancerChain();
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
//super.configure(endpoints);
endpoints.authenticationManager(authenticationManager);
// 将令牌增强器增加到增强器链中
TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();
tokenEnhancerChain.setTokenEnhancers(Arrays.asList(tokenEnhancer()));
endpoints.tokenEnhancer(tokenEnhancerChain);
}
想弄清楚到底怎么弄的,大家自己也可以去看看源码,大概就是你自己自定义一个tokenEnhance,然后将自己定义的tokenEnhance放到tokenEnhanceChain(token增强链),然后设置到endpoint中,这样你就可以自主的修改原有的token内容
3,设置tokenStore
跟clientId,serect一样有多种方式,InMemoryTokenStore,JdbcTokenStore,JTWTokenStore等
auth2.0默认采用InMemoryTokenStore方式,直接将token放在内存中,在单服务中还是比较好的,简单便捷。
JdbcTokenStore是将token存储在数据库中,相比内存的单服务,数据库形式就可以保证多服务共享。auth2.0默认给了一套数据库的结构,然后使用JdbcTokenStore,内部一些功能也已经实现好了,你只要对接上去就好了
现在主要讲另一种JTWTokenStore,关于jwt大家可以读一下沅一峰的jwt文章,下面附上链接
http://www.ruanyifeng.com/blog/2018/07/json_web_token-tutorial.html
读完上面的文章大概应该有所了解了
下面看具体实现,新增如下类,代码如下:
@Configuration
public class JwtTokenConfig {
private final Logger logger = LoggerFactory.getLogger(JwtTokenConfig.class);
public JwtTokenConfig() {logger.info("Loading JwtTokenConfig ...");}
@Bean
public TokenStore jwtTokenStore() {
return new JwtTokenStore(jwtAccessTokenConverter());
}
// 用来生成jwt
@Bean
public JwtAccessTokenConverter jwtAccessTokenConverter() {
JwtAccessTokenConverter jwtAccessTokenConverter = new JwtAccessTokenConverter();
//生成签名的key
//秘签
jwtAccessTokenConverter.setSigningKey("zfh");
return jwtAccessTokenConverter;
}
}
然后在auth2ServerConfig类加增加如下代码
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
//super.configure(endpoints);
endpoints.authenticationManager(authenticationManager);
TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();
tokenEnhancerChain.setTokenEnhancers(Arrays.asList(tokenEnhancer(),jwtAccessTokenConverter));
endpoints.tokenEnhancer(tokenEnhancerChain);
//设置tokenstore
// endpoints.tokenStore(jwtTokenStore)
// .accessTokenConverter(jwtAccessTokenConverter);
}
其实我看了一下就是一个TokenEnhancer,所以就按照Enhancer加到endpoint里面就好了,再请求token之后结果如下
{
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJ1c2VyXzEiLCJzY29wZSI6WyJhcHAiXSwiZXhwIjoxNTQ5NTgwODI2LCJ6ZmgiOiIxMjM0IiwiYXV0aG9yaXRpZXMiOlsiVVNFUiJdLCJqdGkiOiI4ODI0MjNiYy1mYWNmLTRjOTEtYWY4MC0zNDQzNDJjYjI2ZDkiLCJjbGllbnRfaWQiOiJjbGllbnRJZCJ9.vUtzh_EQNkYwqhQYA4rvgp3BPJy3zdC9xFv9b8dz1PA",
"token_type": "bearer",
"expires_in": 43190,
"scope": "app",
"zfh": "1234",
"jti": "882423bc-facf-4c91-af80-344342cb26d9"
}
这是经过两个token增强器所得到的结果,上面的jwt加密是对称加密,大家也可以使用非对称加密方式