From e10f325843c46d0fd48776315fa206de100fc4e4 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Tue, 24 Oct 2023 18:48:12 +0800 Subject: [PATCH] =?UTF-8?q?=E7=BB=9F=E4=B8=80=20boot=20=E5=92=8C=20cloud?= =?UTF-8?q?=20=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../DataPermissionUtilsTest.java | 3 +- .../core/util/DictFrameworkUtilsTest.java | 6 +- .../operatelog/core/aop/OperateLogAspect.java | 3 +- .../social/core/YudaoAuthRequestFactory.java | 9 + .../core/request/AuthWeChatMpRequest.java | 178 ++++++++++++++++++ .../controller/admin/auth/AuthController.java | 2 +- 6 files changed, 194 insertions(+), 7 deletions(-) rename yudao-framework/yudao-spring-boot-starter-biz-data-permission/src/test/java/cn/iocoder/yudao/framework/datapermission/core/{utils => util}/DataPermissionUtilsTest.java (72%) create mode 100644 yudao-framework/yudao-spring-boot-starter-biz-social/src/main/java/cn/iocoder/yudao/framework/social/core/request/AuthWeChatMpRequest.java diff --git a/yudao-framework/yudao-spring-boot-starter-biz-data-permission/src/test/java/cn/iocoder/yudao/framework/datapermission/core/utils/DataPermissionUtilsTest.java b/yudao-framework/yudao-spring-boot-starter-biz-data-permission/src/test/java/cn/iocoder/yudao/framework/datapermission/core/util/DataPermissionUtilsTest.java similarity index 72% rename from yudao-framework/yudao-spring-boot-starter-biz-data-permission/src/test/java/cn/iocoder/yudao/framework/datapermission/core/utils/DataPermissionUtilsTest.java rename to yudao-framework/yudao-spring-boot-starter-biz-data-permission/src/test/java/cn/iocoder/yudao/framework/datapermission/core/util/DataPermissionUtilsTest.java index 234a9fe88..1cc57c258 100644 --- a/yudao-framework/yudao-spring-boot-starter-biz-data-permission/src/test/java/cn/iocoder/yudao/framework/datapermission/core/utils/DataPermissionUtilsTest.java +++ b/yudao-framework/yudao-spring-boot-starter-biz-data-permission/src/test/java/cn/iocoder/yudao/framework/datapermission/core/util/DataPermissionUtilsTest.java @@ -1,7 +1,6 @@ -package cn.iocoder.yudao.framework.datapermission.core.utils; +package cn.iocoder.yudao.framework.datapermission.core.util; import cn.iocoder.yudao.framework.datapermission.core.aop.DataPermissionContextHolder; -import cn.iocoder.yudao.framework.datapermission.core.util.DataPermissionUtils; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.*; diff --git a/yudao-framework/yudao-spring-boot-starter-biz-dict/src/test/java/cn/iocoder/yudao/framework/dict/core/util/DictFrameworkUtilsTest.java b/yudao-framework/yudao-spring-boot-starter-biz-dict/src/test/java/cn/iocoder/yudao/framework/dict/core/util/DictFrameworkUtilsTest.java index cb34cac68..9de6ac326 100644 --- a/yudao-framework/yudao-spring-boot-starter-biz-dict/src/test/java/cn/iocoder/yudao/framework/dict/core/util/DictFrameworkUtilsTest.java +++ b/yudao-framework/yudao-spring-boot-starter-biz-dict/src/test/java/cn/iocoder/yudao/framework/dict/core/util/DictFrameworkUtilsTest.java @@ -1,7 +1,6 @@ package cn.iocoder.yudao.framework.dict.core.util; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; -import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest; import cn.iocoder.yudao.module.system.api.dict.DictDataApi; import cn.iocoder.yudao.module.system.api.dict.dto.DictDataRespDTO; @@ -9,6 +8,7 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.mockito.Mock; +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.Mockito.when; @@ -31,7 +31,7 @@ public class DictFrameworkUtilsTest extends BaseMockitoUnitTest { // mock 数据 DictDataRespDTO dataRespDTO = randomPojo(DictDataRespDTO.class, o -> o.setStatus(CommonStatusEnum.ENABLE.getStatus())); // mock 方法 - when(dictDataApi.getDictData(dataRespDTO.getDictType(), dataRespDTO.getValue())).thenReturn(CommonResult.success(dataRespDTO)); + when(dictDataApi.getDictData(dataRespDTO.getDictType(), dataRespDTO.getValue())).thenReturn(success(dataRespDTO)); // 断言返回值 assertEquals(dataRespDTO.getLabel(), DictFrameworkUtils.getDictDataLabel(dataRespDTO.getDictType(), dataRespDTO.getValue())); } @@ -41,7 +41,7 @@ public class DictFrameworkUtilsTest extends BaseMockitoUnitTest { // mock 数据 DictDataRespDTO resp = randomPojo(DictDataRespDTO.class, o -> o.setStatus(CommonStatusEnum.ENABLE.getStatus())); // mock 方法 - when(dictDataApi.parseDictData(resp.getDictType(), resp.getLabel())).thenReturn(CommonResult.success(resp)); + when(dictDataApi.parseDictData(resp.getDictType(), resp.getLabel())).thenReturn(success(resp)); // 断言返回值 assertEquals(resp.getValue(), DictFrameworkUtils.parseDictDataValue(resp.getDictType(), resp.getLabel())); } diff --git a/yudao-framework/yudao-spring-boot-starter-biz-operatelog/src/main/java/cn/iocoder/yudao/framework/operatelog/core/aop/OperateLogAspect.java b/yudao-framework/yudao-spring-boot-starter-biz-operatelog/src/main/java/cn/iocoder/yudao/framework/operatelog/core/aop/OperateLogAspect.java index 1b3492a76..db430e814 100644 --- a/yudao-framework/yudao-spring-boot-starter-biz-operatelog/src/main/java/cn/iocoder/yudao/framework/operatelog/core/aop/OperateLogAspect.java +++ b/yudao-framework/yudao-spring-boot-starter-biz-operatelog/src/main/java/cn/iocoder/yudao/framework/operatelog/core/aop/OperateLogAspect.java @@ -227,7 +227,8 @@ public class OperateLogAspect { private static void fillMethodFields(OperateLog operateLogObj, ProceedingJoinPoint joinPoint, cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog operateLog, - LocalDateTime startTime, Object result, Throwable exception) {MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature(); + LocalDateTime startTime, Object result, Throwable exception) { + MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature(); operateLogObj.setJavaMethod(methodSignature.toString()); if (operateLog == null || operateLog.logArgs()) { operateLogObj.setJavaMethodArgs(obtainMethodArgs(joinPoint)); diff --git a/yudao-framework/yudao-spring-boot-starter-biz-social/src/main/java/cn/iocoder/yudao/framework/social/core/YudaoAuthRequestFactory.java b/yudao-framework/yudao-spring-boot-starter-biz-social/src/main/java/cn/iocoder/yudao/framework/social/core/YudaoAuthRequestFactory.java index 48069ce8e..97f29ad63 100644 --- a/yudao-framework/yudao-spring-boot-starter-biz-social/src/main/java/cn/iocoder/yudao/framework/social/core/YudaoAuthRequestFactory.java +++ b/yudao-framework/yudao-spring-boot-starter-biz-social/src/main/java/cn/iocoder/yudao/framework/social/core/YudaoAuthRequestFactory.java @@ -4,6 +4,7 @@ import cn.hutool.core.util.EnumUtil; import cn.hutool.core.util.ReflectUtil; import cn.iocoder.yudao.framework.social.core.enums.AuthExtendSource; import cn.iocoder.yudao.framework.social.core.request.AuthWeChatMiniAppRequest; +import cn.iocoder.yudao.framework.social.core.request.AuthWeChatMpRequest; import com.xingyuv.jushauth.cache.AuthStateCache; import com.xingyuv.jushauth.config.AuthConfig; import com.xingyuv.jushauth.config.AuthSource; @@ -13,6 +14,8 @@ import com.xingyuv.justauth.autoconfigure.JustAuthProperties; import java.lang.reflect.Method; +import static com.xingyuv.jushauth.config.AuthDefaultSource.WECHAT_MP; + /** * 第三方授权拓展 request 工厂类 * 为使得拓展配置 {@link AuthConfig} 和默认配置齐平,所以自定义本工厂类 @@ -55,6 +58,12 @@ public class YudaoAuthRequestFactory extends AuthRequestFactory { } protected AuthRequest getExtendRequest(String source) { + // TODO 芋艿:临时兼容 justauth 迁移的类型不对问题; + if (WECHAT_MP.name().equalsIgnoreCase(source)) { + AuthConfig config = properties.getType().get(WECHAT_MP.name()); + return new AuthWeChatMpRequest(config, authStateCache); + } + AuthExtendSource authExtendSource; try { authExtendSource = EnumUtil.fromString(AuthExtendSource.class, source.toUpperCase()); diff --git a/yudao-framework/yudao-spring-boot-starter-biz-social/src/main/java/cn/iocoder/yudao/framework/social/core/request/AuthWeChatMpRequest.java b/yudao-framework/yudao-spring-boot-starter-biz-social/src/main/java/cn/iocoder/yudao/framework/social/core/request/AuthWeChatMpRequest.java new file mode 100644 index 000000000..13b77cd35 --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-biz-social/src/main/java/cn/iocoder/yudao/framework/social/core/request/AuthWeChatMpRequest.java @@ -0,0 +1,178 @@ +package cn.iocoder.yudao.framework.social.core.request; + +import com.alibaba.fastjson.JSONObject; +import com.xingyuv.jushauth.cache.AuthStateCache; +import com.xingyuv.jushauth.config.AuthConfig; +import com.xingyuv.jushauth.config.AuthDefaultSource; +import com.xingyuv.jushauth.enums.AuthResponseStatus; +import com.xingyuv.jushauth.enums.AuthUserGender; +import com.xingyuv.jushauth.enums.scope.AuthWechatMpScope; +import com.xingyuv.jushauth.exception.AuthException; +import com.xingyuv.jushauth.model.AuthCallback; +import com.xingyuv.jushauth.model.AuthResponse; +import com.xingyuv.jushauth.model.AuthToken; +import com.xingyuv.jushauth.model.AuthUser; +import com.xingyuv.jushauth.request.AuthDefaultRequest; +import com.xingyuv.jushauth.utils.AuthScopeUtils; +import com.xingyuv.jushauth.utils.GlobalAuthUtils; +import com.xingyuv.jushauth.utils.HttpUtils; +import com.xingyuv.jushauth.utils.UrlBuilder; + +/** + * 微信公众平台登录 + * + * @author yangkai.shen (https://xkcoding.com) + * @since 1.1.0 + */ +public class AuthWeChatMpRequest extends AuthDefaultRequest { + public AuthWeChatMpRequest(AuthConfig config) { + super(config, AuthDefaultSource.WECHAT_MP); + } + + public AuthWeChatMpRequest(AuthConfig config, AuthStateCache authStateCache) { + super(config, AuthDefaultSource.WECHAT_MP, authStateCache); + } + + /** + * 微信的特殊性,此时返回的信息同时包含 openid 和 access_token + * + * @param authCallback 回调返回的参数 + * @return 所有信息 + */ + @Override + protected AuthToken getAccessToken(AuthCallback authCallback) { + return this.getToken(accessTokenUrl(authCallback.getCode())); + } + + @Override + protected AuthUser getUserInfo(AuthToken authToken) { + String openId = authToken.getOpenId(); + + String response = doGetUserInfo(authToken); + JSONObject object = JSONObject.parseObject(response); + + this.checkResponse(object); + + String location = String.format("%s-%s-%s", object.getString("country"), object.getString("province"), object.getString("city")); + + if (object.containsKey("unionid")) { + authToken.setUnionId(object.getString("unionid")); + } + + return AuthUser.builder() + .rawUserInfo(object) + .username(object.getString("nickname")) + .nickname(object.getString("nickname")) + .avatar(object.getString("headimgurl")) + .location(location) + .uuid(openId) + .gender(AuthUserGender.getWechatRealGender(object.getString("sex"))) + .token(authToken) + .source(source.toString()) + .build(); + } + + @Override + public AuthResponse refresh(AuthToken oldToken) { + return AuthResponse.builder() + .code(AuthResponseStatus.SUCCESS.getCode()) + .data(this.getToken(refreshTokenUrl(oldToken.getRefreshToken()))) + .build(); + } + + /** + * 检查响应内容是否正确 + * + * @param object 请求响应内容 + */ + private void checkResponse(JSONObject object) { + if (object.containsKey("errcode")) { + throw new AuthException(object.getIntValue("errcode"), object.getString("errmsg")); + } + } + + /** + * 获取token,适用于获取access_token和刷新token + * + * @param accessTokenUrl 实际请求token的地址 + * @return token对象 + */ + private AuthToken getToken(String accessTokenUrl) { + String response = new HttpUtils(config.getHttpConfig()).get(accessTokenUrl).getBody(); + JSONObject accessTokenObject = JSONObject.parseObject(response); + + this.checkResponse(accessTokenObject); + + return AuthToken.builder() + .accessToken(accessTokenObject.getString("access_token")) + .refreshToken(accessTokenObject.getString("refresh_token")) + .expireIn(accessTokenObject.getIntValue("expires_in")) + .openId(accessTokenObject.getString("openid")) + .scope(accessTokenObject.getString("scope")) + .build(); + } + + /** + * 返回带{@code state}参数的授权url,授权回调时会带上这个{@code state} + * + * @param state state 验证授权流程的参数,可以防止csrf + * @return 返回授权地址 + * @since 1.9.3 + */ + @Override + public String authorize(String state) { + return UrlBuilder.fromBaseUrl(source.authorize()) + .queryParam("appid", config.getClientId()) + .queryParam("redirect_uri", GlobalAuthUtils.urlEncode(config.getRedirectUri())) + .queryParam("response_type", "code") + .queryParam("scope", this.getScopes(",", false, AuthScopeUtils.getDefaultScopes(AuthWechatMpScope.values()))) + .queryParam("state", getRealState(state).concat("#wechat_redirect")) + .build(); + } + + /** + * 返回获取accessToken的url + * + * @param code 授权码 + * @return 返回获取accessToken的url + */ + @Override + protected String accessTokenUrl(String code) { + return UrlBuilder.fromBaseUrl(source.accessToken()) + .queryParam("appid", config.getClientId()) + .queryParam("secret", config.getClientSecret()) + .queryParam("code", code) + .queryParam("grant_type", "authorization_code") + .build(); + } + + /** + * 返回获取userInfo的url + * + * @param authToken 用户授权后的token + * @return 返回获取userInfo的url + */ + @Override + protected String userInfoUrl(AuthToken authToken) { + return UrlBuilder.fromBaseUrl(source.userInfo()) + .queryParam("access_token", authToken.getAccessToken()) + .queryParam("openid", authToken.getOpenId()) + .queryParam("lang", "zh_CN") + .build(); + } + + /** + * 返回获取userInfo的url + * + * @param refreshToken getAccessToken方法返回的refreshToken + * @return 返回获取userInfo的url + */ + @Override + protected String refreshTokenUrl(String refreshToken) { + return UrlBuilder.fromBaseUrl(source.refresh()) + .queryParam("appid", config.getClientId()) + .queryParam("grant_type", "refresh_token") + .queryParam("refresh_token", refreshToken) + .build(); + } +} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/AuthController.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/AuthController.java index ff04a7512..c2eae8d38 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/AuthController.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/AuthController.java @@ -148,7 +148,7 @@ public class AuthController { }) public CommonResult socialLogin(@RequestParam("type") Integer type, @RequestParam("redirectUri") String redirectUri) { - return CommonResult.success(socialClientService.getAuthorizeUrl( + return success(socialClientService.getAuthorizeUrl( type, UserTypeEnum.ADMIN.getValue(), redirectUri)); }