JustAuth扩展:支持自动获得回调域名、使用redission作为Cache

本文主要是介绍JustAuth扩展:支持自动获得回调域名、使用redission作为Cache,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

当前使用的版本:
 

just_auth_version = '1.16.6'
just_auth_starter_version = '1.4.0'
"me.zhyd.oauth:JustAuth:${just_auth_version}", //多渠道登录
"com.xkcoding.justauth:justauth-spring-boot-starter:${just_auth_starter_version}" //启动器

在JustAuth整合过程中,遇到两个功能扩展:
1)JustAuth默认使用sping-data-redis作为缓存接口,当前系统没有使用该redis驱动,由于已经使用了redission,不希望引入更多的架构。故需要扩展JustAuthCache接口
2)JustAuth配置的登录回调地址必须写完整的域名。本着从哪里来,回哪里去的原则,回调的域名地址,95%需求都会跟请求的域名地址一致。这样只需要在请求时获得请求的域名地址即可,不用在配置文件里额外配置。让配置文件的redirect-uri真正成为URI而不是URL

自定义缓存

自定义缓存按照文档的扩展即可,项目使用redission,如下定义一个CacheBean

package org.ccframe.commons.auth;import me.zhyd.oauth.cache.AuthStateCache;
import org.ccframe.config.GlobalEx;
import org.redisson.api.RBucket;
import org.redisson.api.RedissonClient;
import org.redisson.client.codec.StringCodec;import java.util.concurrent.TimeUnit;/*** JustAuth三方登录缓存管理.* @author Jim 2024/03/08*/
public class CcAuthStateCache implements AuthStateCache {private RedissonClient redissonClient;public CcAuthStateCache(RedissonClient redissonClient){this.redissonClient = redissonClient;}/*** 存入缓存** @param key   缓存key* @param value 缓存内容*/@Overridepublic void cache(String key, String value) {RBucket<String> bucket = redissonClient.getBucket(GlobalEx.CACHEREGION_THIRD_AUTH + key);bucket.set(value, 10, TimeUnit.MINUTES); // 10分钟还无法三方绑定的登录,则无法进行绑定}/*** 存入缓存** @param key     缓存key* @param value   缓存内容* @param timeout 指定缓存过期时间(毫秒)*/@Overridepublic void cache(String key, String value, long timeout) {RBucket<String> bucket = redissonClient.getBucket(GlobalEx.CACHEREGION_THIRD_AUTH + key, StringCodec.INSTANCE);bucket.set(value, timeout, TimeUnit.MILLISECONDS);}/*** 获取缓存内容** @param key 缓存key* @return 缓存内容*/@Overridepublic String get(String key) {RBucket<String> bucket = redissonClient.getBucket(GlobalEx.CACHEREGION_THIRD_AUTH + key, StringCodec.INSTANCE);return bucket.get();}/*** 是否存在key,如果对应key的value值已过期,也返回false** @param key 缓存key* @return true:存在key,并且value没过期;false:key不存在或者已过期*/@Overridepublic boolean containsKey(String key) {return redissonClient.getBucket(GlobalEx.CACHEREGION_THIRD_AUTH + key).isExists();}
}

实现真正的REDIRECT URI

先看看实现后的效果,整合后,CcFrame的公共配置只需要如下配置:
 

justauth:enabled: false #原来的关闭掉,因为自己写了个新的CcAuthRequestFactory,使用下面的开关cc-enabled: truecache:type: customtype:QQ: #前台登录client-id: ${app.third-oauth.QQ.client-id:}client-secret: ${app.third-oauth.QQ.client-secret:}redirect-uri: /api/common/thirdOauthCallback/qqunion-id: falseGITEE: #后台登录client-id: ${app.third-oauth.GITEE.client-id:}client-secret: ${app.third-oauth.GITEE.client-secret:}redirect-uri: /admin/common/thirdOauthCallback/giteeDINGTALK: #后台登录client-id: ${app.third-oauth.DINGTALK.client-id:}client-secret: ${app.third-oauth.DINGTALK.client-secret:}redirect-uri: /admin/common/thirdOauthCallback/dingtalk

redirect-uri不关心回调地址从哪里来,这样便省去了不同项目域名地址之间差异,我只关心URI

而项目里的配置则更简单:

app:third-oauth:GITEE:client-id: ??client-secret: ??

即可针对不同的项目及环境实现接入。

扩展点如下:
针对不支持URI的问题,本打算extend AuthRequestFactory的,结果发现大部分方法都private了,不方便扩展。再检查下用法发现引入的地方是在用户代码部分,因此索性复制了重写了

/** Copyright (c) 2019-2029, xkcoding & Yangkai.Shen & 沈扬凯 (237497819@qq.com & xkcoding.com).* <p>* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;* you may not use this file except in compliance with the License.* You may obtain a copy of the License at* <p>* http://www.gnu.org/licenses/lgpl.html* <p>* Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an "AS IS" BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.**/package org.ccframe.commons.auth;import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.EnumUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;
import com.xkcoding.http.config.HttpConfig;
import com.xkcoding.justauth.autoconfigure.ExtendProperties;
import com.xkcoding.justauth.autoconfigure.JustAuthProperties;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import me.zhyd.oauth.cache.AuthStateCache;
import me.zhyd.oauth.config.AuthConfig;
import me.zhyd.oauth.config.AuthDefaultSource;
import me.zhyd.oauth.config.AuthSource;
import me.zhyd.oauth.enums.AuthResponseStatus;
import me.zhyd.oauth.exception.AuthException;
import me.zhyd.oauth.request.*;
import org.springframework.beans.BeanUtils;
import org.springframework.util.CollectionUtils;import java.net.InetSocketAddress;
import java.net.Proxy;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;/*** private引入太多,直接复制了改了.** <p>* AuthRequest工厂类* </p>** @author yangkai.shen* @date Created in 2019-07-22 14:21*/
@Slf4j
@RequiredArgsConstructor
public class CcAuthRequestFactory {private final JustAuthProperties properties;private final AuthStateCache authStateCache;/*** 返回当前Oauth列表** @return Oauth列表*/@SuppressWarnings({"unchecked", "rawtypes"})public List<String> oauthList() {// 默认列表List<String> defaultList = new ArrayList<>(properties.getType().keySet());// 扩展列表List<String> extendList = new ArrayList<>();ExtendProperties extend = properties.getExtend();if (null != extend) {Class enumClass = extend.getEnumClass();List<String> names = EnumUtil.getNames(enumClass);// 扩展列表extendList = extend.getConfig().keySet().stream().filter(x -> names.contains(x.toUpperCase())).map(String::toUpperCase).collect(Collectors.toList());}// 合并return (List<String>) CollUtil.addAll(defaultList, extendList);}/*** 返回AuthRequest对象** @param source {@link AuthSource}* @param requestBaseUrl redirectUri 请求URI的前缀,这样配置里只需要写URI了* @return {@link AuthRequest}*/public AuthRequest get(String source, String requestBaseUrl) {if (StrUtil.isBlank(source)) {throw new AuthException(AuthResponseStatus.NO_AUTH_SOURCE);}// 获取 JustAuth 中已存在的AuthRequest authRequest = getDefaultRequest(source, requestBaseUrl);// 如果获取不到则尝试取自定义的if (authRequest == null) {authRequest = getExtendRequest(properties.getExtend().getEnumClass(), source);}if (authRequest == null) {throw new AuthException(AuthResponseStatus.UNSUPPORTED);}return authRequest;}/*** 获取自定义的 request** @param clazz  枚举类 {@link AuthSource}* @param source {@link AuthSource}* @return {@link AuthRequest}*/@SuppressWarnings({"unchecked", "rawtypes"})private AuthRequest getExtendRequest(Class clazz, String source) {String upperSource = source.toUpperCase();try {EnumUtil.fromString(clazz, upperSource);} catch (IllegalArgumentException e) {// 无自定义匹配return null;}Map<String, ExtendProperties.ExtendRequestConfig> extendConfig = properties.getExtend().getConfig();// key 转大写Map<String, ExtendProperties.ExtendRequestConfig> upperConfig = new HashMap<>(6);extendConfig.forEach((k, v) -> upperConfig.put(k.toUpperCase(), v));ExtendProperties.ExtendRequestConfig extendRequestConfig = upperConfig.get(upperSource);if (extendRequestConfig != null) {// 配置 http configconfigureHttpConfig(upperSource, extendRequestConfig, properties.getHttpConfig());Class<? extends AuthRequest> requestClass = extendRequestConfig.getRequestClass();if (requestClass != null) {// 反射获取 Request 对象,所以必须实现 2 个参数的构造方法return ReflectUtil.newInstance(requestClass, (AuthConfig) extendRequestConfig, authStateCache);}}return null;}/*** 获取默认的 Request** @param source {@link AuthSource}* @return {@link AuthRequest}*/private AuthRequest getDefaultRequest(String source, String requestBaseUrl) {AuthDefaultSource authDefaultSource;try {authDefaultSource = EnumUtil.fromString(AuthDefaultSource.class, source.toUpperCase());} catch (IllegalArgumentException e) {// 无自定义匹配return null;}AuthConfig config = properties.getType().get(authDefaultSource.name());// 找不到对应关系,直接返回空if (config == null) {return null;}if(!config.getRedirectUri().startsWith("http")){ // 克隆并修改回调地址AuthConfig newConfig = new AuthConfig();BeanUtils.copyProperties(config, newConfig);newConfig.setRedirectUri(requestBaseUrl + newConfig.getRedirectUri());config = newConfig;}// 配置 http configconfigureHttpConfig(authDefaultSource.name(), config, properties.getHttpConfig());switch (authDefaultSource) {case GITHUB:return new AuthGithubRequest(config, authStateCache);case WEIBO:return new AuthWeiboRequest(config, authStateCache);case GITEE:return new AuthGiteeRequest(config, authStateCache);case DINGTALK:return new AuthDingTalkRequest(config, authStateCache);case DINGTALK_ACCOUNT:return new AuthDingTalkAccountRequest(config, authStateCache);case BAIDU:return new AuthBaiduRequest(config, authStateCache);case CSDN:return new AuthCsdnRequest(config, authStateCache);case CODING:return new AuthCodingRequest(config, authStateCache);case OSCHINA:return new AuthOschinaRequest(config, authStateCache);case ALIPAY:return new AuthAlipayRequest(config, authStateCache);case QQ:return new AuthQqRequest(config, authStateCache);case WECHAT_OPEN:return new AuthWeChatOpenRequest(config, authStateCache);case WECHAT_MP:return new AuthWeChatMpRequest(config, authStateCache);case WECHAT_ENTERPRISE:return new AuthWeChatEnterpriseQrcodeRequest(config, authStateCache);case WECHAT_ENTERPRISE_WEB:return new AuthWeChatEnterpriseWebRequest(config, authStateCache);case TAOBAO:return new AuthTaobaoRequest(config, authStateCache);case GOOGLE:return new AuthGoogleRequest(config, authStateCache);case FACEBOOK:return new AuthFacebookRequest(config, authStateCache);case DOUYIN:return new AuthDouyinRequest(config, authStateCache);case LINKEDIN:return new AuthLinkedinRequest(config, authStateCache);case MICROSOFT:return new AuthMicrosoftRequest(config, authStateCache);case MI:return new AuthMiRequest(config, authStateCache);case TOUTIAO:return new AuthToutiaoRequest(config, authStateCache);case TEAMBITION:return new AuthTeambitionRequest(config, authStateCache);case RENREN:return new AuthRenrenRequest(config, authStateCache);case PINTEREST:return new AuthPinterestRequest(config, authStateCache);case STACK_OVERFLOW:return new AuthStackOverflowRequest(config, authStateCache);case HUAWEI:return new AuthHuaweiRequest(config, authStateCache);case GITLAB:return new AuthGitlabRequest(config, authStateCache);case KUJIALE:return new AuthKujialeRequest(config, authStateCache);case ELEME:return new AuthElemeRequest(config, authStateCache);case MEITUAN:return new AuthMeituanRequest(config, authStateCache);case TWITTER:return new AuthTwitterRequest(config, authStateCache);case FEISHU:return new AuthFeishuRequest(config, authStateCache);case JD:return new AuthJdRequest(config, authStateCache);case ALIYUN:return new AuthAliyunRequest(config, authStateCache);case XMLY:return new AuthXmlyRequest(config, authStateCache);case AMAZON:return new AuthAmazonRequest(config, authStateCache);case SLACK:return new AuthSlackRequest(config, authStateCache);case LINE:return new AuthLineRequest(config, authStateCache);case OKTA:return new AuthOktaRequest(config, authStateCache);default:return null;}}/*** 配置 http 相关的配置** @param authSource {@link AuthSource}* @param authConfig {@link AuthConfig}*/private void configureHttpConfig(String authSource, AuthConfig authConfig, JustAuthProperties.JustAuthHttpConfig httpConfig) {if (null == httpConfig) {return;}Map<String, JustAuthProperties.JustAuthProxyConfig> proxyConfigMap = httpConfig.getProxy();if (CollectionUtils.isEmpty(proxyConfigMap)) {return;}JustAuthProperties.JustAuthProxyConfig proxyConfig = proxyConfigMap.get(authSource);if (null == proxyConfig) {return;}authConfig.setHttpConfig(HttpConfig.builder().timeout(httpConfig.getTimeout()).proxy(new Proxy(Proxy.Type.valueOf(proxyConfig.getType()), new InetSocketAddress(proxyConfig.getHostname(), proxyConfig.getPort()))).build());}
}

这样一来,实际调用的时候,Autowire CcAuthRequestFactory而不是AuthRequestFactory。而在get方法的时候,增加了requestBaseUrl调用用来自动添加前缀地址。requestBaseUrl则是从Controller请求自动从前端请求抓取而来:
 

    @Autowiredprivate CcAuthRequestFactory factory;@GetMapping(value = "thirdOauth")@ApiOperation(value = "三方登录并跳转")@SneakyThrowspublic void thirdOauth(String type,@ApiIgnore RequestSite adminSite, HttpServletResponse response){ //跳转三方登录,换取code等AuthRequest authRequest = factory.get(type, adminSite.getRequestBaseUrl());response.setStatus(302); //支持HTTP重定向到HTTPSresponse.sendRedirect(authRequest.authorize(AuthStateUtils.createState()));}

BTW.三方登录的请求开关也被改了,使用cc-enabled而不是enabled,避免将原来的RequestFactory也自动初始化

至于RequestSite adminSite如何自动注入的请看我的另一篇文章,你注入ServletHttpRequest去实现一样。

这样便支持了前面配置文件里的直接书写URI,URL则是调用Controller的请求域名及IP:
redirect-uri: /api/common/thirdOauthCallback/qq

配置省事了,省一点算一点,优秀的系统必须是一点点简化而来的

这篇关于JustAuth扩展:支持自动获得回调域名、使用redission作为Cache的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/797137

相关文章

中文分词jieba库的使用与实景应用(一)

知识星球:https://articles.zsxq.com/id_fxvgc803qmr2.html 目录 一.定义: 精确模式(默认模式): 全模式: 搜索引擎模式: paddle 模式(基于深度学习的分词模式): 二 自定义词典 三.文本解析   调整词出现的频率 四. 关键词提取 A. 基于TF-IDF算法的关键词提取 B. 基于TextRank算法的关键词提取

使用SecondaryNameNode恢复NameNode的数据

1)需求: NameNode进程挂了并且存储的数据也丢失了,如何恢复NameNode 此种方式恢复的数据可能存在小部分数据的丢失。 2)故障模拟 (1)kill -9 NameNode进程 [lytfly@hadoop102 current]$ kill -9 19886 (2)删除NameNode存储的数据(/opt/module/hadoop-3.1.4/data/tmp/dfs/na

Hadoop数据压缩使用介绍

一、压缩原则 (1)运算密集型的Job,少用压缩 (2)IO密集型的Job,多用压缩 二、压缩算法比较 三、压缩位置选择 四、压缩参数配置 1)为了支持多种压缩/解压缩算法,Hadoop引入了编码/解码器 2)要在Hadoop中启用压缩,可以配置如下参数

Makefile简明使用教程

文章目录 规则makefile文件的基本语法:加在命令前的特殊符号:.PHONY伪目标: Makefilev1 直观写法v2 加上中间过程v3 伪目标v4 变量 make 选项-f-n-C Make 是一种流行的构建工具,常用于将源代码转换成可执行文件或者其他形式的输出文件(如库文件、文档等)。Make 可以自动化地执行编译、链接等一系列操作。 规则 makefile文件

使用opencv优化图片(画面变清晰)

文章目录 需求影响照片清晰度的因素 实现降噪测试代码 锐化空间锐化Unsharp Masking频率域锐化对比测试 对比度增强常用算法对比测试 需求 对图像进行优化,使其看起来更清晰,同时保持尺寸不变,通常涉及到图像处理技术如锐化、降噪、对比度增强等 影响照片清晰度的因素 影响照片清晰度的因素有很多,主要可以从以下几个方面来分析 1. 拍摄设备 相机传感器:相机传

csu 1446 Problem J Modified LCS (扩展欧几里得算法的简单应用)

这是一道扩展欧几里得算法的简单应用题,这题是在湖南多校训练赛中队友ac的一道题,在比赛之后请教了队友,然后自己把它a掉 这也是自己独自做扩展欧几里得算法的题目 题意:把题意转变下就变成了:求d1*x - d2*y = f2 - f1的解,很明显用exgcd来解 下面介绍一下exgcd的一些知识点:求ax + by = c的解 一、首先求ax + by = gcd(a,b)的解 这个

pdfmake生成pdf的使用

实际项目中有时会有根据填写的表单数据或者其他格式的数据,将数据自动填充到pdf文件中根据固定模板生成pdf文件的需求 文章目录 利用pdfmake生成pdf文件1.下载安装pdfmake第三方包2.封装生成pdf文件的共用配置3.生成pdf文件的文件模板内容4.调用方法生成pdf 利用pdfmake生成pdf文件 1.下载安装pdfmake第三方包 npm i pdfma

零基础学习Redis(10) -- zset类型命令使用

zset是有序集合,内部除了存储元素外,还会存储一个score,存储在zset中的元素会按照score的大小升序排列,不同元素的score可以重复,score相同的元素会按照元素的字典序排列。 1. zset常用命令 1.1 zadd  zadd key [NX | XX] [GT | LT]   [CH] [INCR] score member [score member ...]

科研绘图系列:R语言扩展物种堆积图(Extended Stacked Barplot)

介绍 R语言的扩展物种堆积图是一种数据可视化工具,它不仅展示了物种的堆积结果,还整合了不同样本分组之间的差异性分析结果。这种图形表示方法能够直观地比较不同物种在各个分组中的显著性差异,为研究者提供了一种有效的数据解读方式。 加载R包 knitr::opts_chunk$set(warning = F, message = F)library(tidyverse)library(phyl

git使用的说明总结

Git使用说明 下载安装(下载地址) macOS: Git - Downloading macOS Windows: Git - Downloading Windows Linux/Unix: Git (git-scm.com) 创建新仓库 本地创建新仓库:创建新文件夹,进入文件夹目录,执行指令 git init ,用以创建新的git 克隆仓库 执行指令用以创建一个本地仓库的