背景说明
一个账号只能一处登录,类似的业务需求在现有后管类系统是非常常见的。 但在原有的 spring security oauth2 令牌方法流程(所谓的登录)无法满足类似的需求。
我们先来看 tokenendpoint
的方法流程
客户端 带参访问 /oauth/token 接口,最后去调用 tokengranter
另外要注意:突破高薪java架构项目经验永远是核心,如果你没有最新java架构实战教程及大厂30k+面试宝典,可以去小编的java架构学习.裙 :七吧伞吧零而衣零伞 (数字的谐音)转换下可以找到了,里面很多新java架构项目教程,还可以跟老司机交流讨教!
tokengranter
根据不同的授权类型,获取用户认证信息 并去调用tokenservices
生成令牌
重新 tokenservice
- 重写发放逻辑
createaccesstoken
,当用户管理的令牌存在时则删除重新创建,这样会导致之前登陆获取的token 失效,顺理成章的被挤掉。
@transactional public oauth2accesstoken createaccesstoken() { oauth2accesstoken existingaccesstoken = tokenstore.getaccesstoken(authentication); oauth2refreshtoken refreshtoken = null; // 重写此处,当用户关联的token 存在时,删除原有令牌 if (existingaccesstoken != null) { tokenstore.removeaccesstoken(existingaccesstoken); } else if (refreshtoken instanceof expiringoauth2refreshtoken) { expiringoauth2refreshtoken expiring = (expiringoauth2refreshtoken) refreshtoken; if (system.currenttimemillis() > expiring.getexpiration().gettime()) { refreshtoken = createrefreshtoken(authentication); } }
oauth2accesstoken accesstoken = createaccesstoken(authentication, refreshtoken); tokenstore.storeaccesstoken(accesstoken, authentication); // in case it was modified refreshtoken = accesstoken.getrefreshtoken(); if (refreshtoken != null) { tokenstore.storerefreshtoken(refreshtoken, authentication); } return accesstoken; } 复制代码
复制代码
复制代码
重写 token key 生成逻辑
- 如上代码,我们实现用户单一终端的唯一性登录,什么是单一终端 我们可以类比 qq 登录 移动端和 pc 端可以同时登录,但 移动端 和移动端不能同时在线。
- 如何能够实现 在不同客户端也能够唯一性登录呢?
先来看上文源码 oauth2accesstoken existingaccesstoken=tokenstore.getaccesstoken(authentication);
是如何根据用户信息判断 token 存在的呢?
public oauth2accesstoken getaccesstoken(oauth2authentication authentication) { string key = authenticationkeygenerator.extractkey(authentication); // redis 查询逻辑,根据 key return accesstoken; 复制代码
} 复制代码
- authenticationkeygenerator key值生成器 默认情况下根据
username
/clientid
/scope
参数组合生成唯一token
public string extractkey(oauth2authentication authentication) { map<string, string> values = new linkedhashmap<string, string>(); oauth2request authorizationrequest = authentication.getoauth2request(); if (!authentication.isclientonly()) { values.put(username, authentication.getname()); } values.put(client_id, authorizationrequest.getclientid()); if (authorizationrequest.getscope() != null) { values.put(scope, oauth2utils.formatparameterlist(new treeset<string>(authorizationrequest.getscope()))); } return generatekey(values); } 复制代码
- 若想实现,多终端的唯一性登录,只需要使得同一个用户在多个终端生成的
token
一致,加上上文提到的 createtoken 修改逻辑,既去掉extractkey
的 clientid 条件,不区分终端即可
public string extractkey(oauth2authentication authentication) { map<string, string> values = new linkedhashmap<string, string>(); oauth2request authorizationrequest = authentication.getoauth2request(); if (!authentication.isclientonly()) { values.put(username, authentication.getname()); } if (authorizationrequest.getscope() != null) { values.put(scope, oauth2utils.formatparameterlist(new treeset<string>(authorizationrequest.getscope()))); } return generatekey(values); } 复制代码
- 最后在 authserver 中注入新的 tokenservice 即可
最后注意:突破高薪java架构项目经验永远是核心,如果你没有最新java架构实战教程及大厂30k+面试宝典,可以去小编的java架构学习.裙 :七吧伞吧零而衣零伞 (数字的谐音)转换下可以找到了,里面很多新java架构项目教程,还可以跟老司机交流讨教!本文的文字及图片来源于网络加上自己的想法,仅供学习、交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以作处理