欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

如何用Spring Security OAuth2 实现登录互踢,面试必学

程序员文章站 2023-01-28 10:37:46
背景说明 一个账号只能一处登录,类似的业务需求在现有后管类系统是非常常见的。 但在原有的 spring security oauth2 令牌方法流程(所谓的登录)无法满足类似的需求。 我们先来看 TokenEndpoint 的方法流程 客户端 带参访问 /oauth/token 接口,最后去调用 T ......

 

如何用Spring Security OAuth2 实现登录互踢,面试必学

背景说明

一个账号只能一处登录,类似的业务需求在现有后管类系统是非常常见的。 但在原有的 spring security oauth2 令牌方法流程(所谓的登录)无法满足类似的需求。

我们先来看 tokenendpoint 的方法流程

客户端 带参访问 /oauth/token 接口,最后去调用 tokengranter
另外要注意:突破高薪java架构项目经验永远是核心,如果你没有最新java架构实战教程及大厂30k+面试宝典,可以去小编的java架构学习.裙 :七吧伞吧零而衣零伞 (数字的谐音)转换下可以找到了,里面很多新java架构项目教程,还可以跟老司机交流讨教! 

如何用Spring Security OAuth2 实现登录互踢,面试必学

tokengranter 根据不同的授权类型,获取用户认证信息 并去调用tokenservices 生成令牌

如何用Spring Security OAuth2 实现登录互踢,面试必学

重新 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架构项目教程,还可以跟老司机交流讨教! 

    本文的文字及图片来源于网络加上自己的想法,仅供学习、交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以作处理