mirror of
https://gitee.com/xiaonuobase/snowy.git
synced 2026-10-06 06:52:58 +08:00
【底座】采纳建议 #IJVMPI 第三方登录支持“微信小程序”登录,已增加后端相关功能,前端需暂未使用wx.login,需自行增加
This commit is contained in:
Binary file not shown.
|
After Width: | Height: | Size: 1.7 KiB |
@@ -24,6 +24,9 @@
|
||||
<a v-if="formData.SNOWY_THIRD_WECHAT_ALLOW_LOGIN_FLAG" @click="getLoginRenderUrl('WECHAT')">
|
||||
<img style="width: 32px; height: 32px" src="/src/assets/images/authSource/wechat.png" alt="" />
|
||||
</a>
|
||||
<a v-if="formData.SNOWY_THIRD_WECHAT_MINI_ALLOW_LOGIN_FLAG" @click="getLoginRenderUrl('WECHAT_MINI')">
|
||||
<img style="width: 32px; height: 32px" src="/src/assets/images/authSource/wechatmini.png" alt="" />
|
||||
</a>
|
||||
<a v-if="formData.SNOWY_THIRD_DINGTALK_ALLOW_LOGIN_FLAG" @click="getLoginRenderUrl('DINGTALK')">
|
||||
<img style="width: 32px; height: 32px" src="/src/assets/images/authSource/dingtalk.png" alt="" />
|
||||
</a>
|
||||
@@ -60,6 +63,7 @@
|
||||
import { ref, computed } from 'vue'
|
||||
import configApi from '@/api/dev/configApi'
|
||||
import thirdApi from '@/api/auth/thirdApi'
|
||||
import {message} from "ant-design-vue";
|
||||
const formData = ref({})
|
||||
const hasAnyThirdLogin = computed(() => {
|
||||
return Object.values(formData.value).some((v) => v === true)
|
||||
@@ -80,13 +84,17 @@
|
||||
}
|
||||
}
|
||||
const getLoginRenderUrl = (platform) => {
|
||||
const param = {
|
||||
platform: platform,
|
||||
clientType: 'B'
|
||||
if(platform === 'WECHAT_MINI') {
|
||||
message.warning('请在微信小程序环境使用微信小程序登录')
|
||||
} else {
|
||||
const param = {
|
||||
platform: platform,
|
||||
clientType: 'B'
|
||||
}
|
||||
thirdApi.thirdRender(param).then((data) => {
|
||||
window.location.href = data.authorizeUrl
|
||||
})
|
||||
}
|
||||
thirdApi.thirdRender(param).then((data) => {
|
||||
window.location.href = data.authorizeUrl
|
||||
})
|
||||
}
|
||||
getConfigSysThirdAllowFlagList()
|
||||
</script>
|
||||
|
||||
@@ -176,7 +176,7 @@
|
||||
}
|
||||
]
|
||||
// 操作栏通过权限判断是否显示
|
||||
if (hasPerm(['bizNoticeEdit', 'bizNoticeDelete'])) {
|
||||
if (hasPerm(['bizNoticeEdit', 'bizNoticeDelete', 'bizNoticeDetail'])) {
|
||||
columns.push({
|
||||
title: '操作',
|
||||
dataIndex: 'action',
|
||||
|
||||
@@ -84,6 +84,18 @@
|
||||
</template>
|
||||
<wechatThirdForm />
|
||||
</a-tab-pane>
|
||||
<a-tab-pane key="wechatMiniThird">
|
||||
<template #tab>
|
||||
<span>
|
||||
<img
|
||||
src="@/assets/images/authSource/wechatmini.png"
|
||||
style="width: 20px; height: 20px; margin-right: 8px; vertical-align: middle"
|
||||
/>
|
||||
微信小程序
|
||||
</span>
|
||||
</template>
|
||||
<wechatMiniThirdForm />
|
||||
</a-tab-pane>
|
||||
<a-tab-pane key="dingTalkThird">
|
||||
<template #tab>
|
||||
<span>
|
||||
@@ -203,6 +215,7 @@
|
||||
import SamlThirdForm from './samlThirdForm.vue'
|
||||
import IamThirdForm from './iamThirdForm.vue'
|
||||
import WechatThirdForm from './wechatThirdForm.vue'
|
||||
import WechatMiniThirdForm from './wechatMiniThirdForm.vue'
|
||||
import DingTalkThirdForm from './dingTalkThirdForm.vue'
|
||||
import WorkWechatThirdForm from './workWechatThirdForm.vue'
|
||||
import FeiShuThirdForm from './feiShuThirdForm.vue'
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
|
||||
<a-form-item ame="SNOWY_THIRD_SAML_CERTIFICATE" v-if="formData.SNOWY_THIRD_SAML_ALLOW_LOGIN_FLAG">
|
||||
<a-form-item name="SNOWY_THIRD_SAML_CERTIFICATE" v-if="formData.SNOWY_THIRD_SAML_ALLOW_LOGIN_FLAG">
|
||||
<template #label>
|
||||
<a-tooltip>
|
||||
<template #title> AuthSamlClient生成自签证书后填入 </template>
|
||||
|
||||
@@ -0,0 +1,123 @@
|
||||
<template>
|
||||
<a-spin :spinning="loadSpinning">
|
||||
<a-alert message="微信小程序需要前端处于微信小程序环境,本系统仅提供后端功能,前端需自行开发" type="info" :closable="false" class="mb-2" show-icon />
|
||||
<a-form
|
||||
ref="formRef"
|
||||
:model="formData"
|
||||
:rules="formRules"
|
||||
layout="vertical"
|
||||
:label-col="{ ...layout.labelCol, offset: 0 }"
|
||||
:wrapper-col="{ ...layout.wrapperCol, offset: 0 }"
|
||||
>
|
||||
<a-row :gutter="8">
|
||||
<a-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
|
||||
<a-form-item label="是否允许微信小程序登录:" name="SNOWY_THIRD_WECHAT_MINI_ALLOW_LOGIN_FLAG">
|
||||
<a-switch
|
||||
v-model:checked="formData.SNOWY_THIRD_WECHAT_MINI_ALLOW_LOGIN_FLAG"
|
||||
checked-children="是"
|
||||
un-checked-children="否"
|
||||
placeholder="请选择是否允许微小程序信登录"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
|
||||
<a-form-item
|
||||
label="clientId:"
|
||||
name="SNOWY_THIRD_WECHAT_MINI_CLIENT_ID"
|
||||
v-if="formData.SNOWY_THIRD_WECHAT_MINI_ALLOW_LOGIN_FLAG"
|
||||
>
|
||||
<a-input v-model:value="formData.SNOWY_THIRD_WECHAT_MINI_CLIENT_ID" placeholder="请输入clientId" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
|
||||
<a-form-item
|
||||
label="clientSecret:"
|
||||
name="SNOWY_THIRD_WECHAT_MINI_CLIENT_SECRET"
|
||||
v-if="formData.SNOWY_THIRD_WECHAT_MINI_ALLOW_LOGIN_FLAG"
|
||||
>
|
||||
<a-input v-model:value="formData.SNOWY_THIRD_WECHAT_MINI_CLIENT_SECRET" placeholder="请输入clientSecret" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
|
||||
<a-form-item>
|
||||
<a-space>
|
||||
<a-button type="primary" :loading="submitLoading" @click="onSubmit()">保存</a-button>
|
||||
<a-button @click="() => formRef.resetFields()">重置</a-button>
|
||||
</a-space>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</a-form>
|
||||
</a-spin>
|
||||
</template>
|
||||
|
||||
<script setup name="wechatThirdForm">
|
||||
import { cloneDeep } from 'lodash-es'
|
||||
import { required } from '@/utils/formRules'
|
||||
import { message } from 'ant-design-vue'
|
||||
import configApi from '@/api/dev/configApi'
|
||||
|
||||
const formRef = ref()
|
||||
const formData = ref({})
|
||||
const submitLoading = ref(false)
|
||||
const loadSpinning = ref(true)
|
||||
|
||||
// 查询此界面的配置项,并转为表单
|
||||
const param = {
|
||||
category: 'THIRD_WECHAT_MINI'
|
||||
}
|
||||
configApi.configList(param).then((data) => {
|
||||
loadSpinning.value = false
|
||||
if (data) {
|
||||
data.forEach((item) => {
|
||||
formData.value[item.configKey] = transferBooleanInValue(item.configValue)
|
||||
})
|
||||
} else {
|
||||
message.warning('表单项不存在,请初始化数据库')
|
||||
}
|
||||
})
|
||||
// 转换值
|
||||
const transferBooleanInValue = (value) => {
|
||||
if (value === 'true' || value === 'false') {
|
||||
return value === 'true'
|
||||
} else {
|
||||
return value
|
||||
}
|
||||
}
|
||||
// 默认要校验的
|
||||
const formRules = {
|
||||
SNOWY_THIRD_WECHAT_MINI_ALLOW_LOGIN_FLAG: [required('请选择是否允许微信小程序登录')],
|
||||
SNOWY_THIRD_WECHAT_MINI_CLIENT_ID: [required('请输入clientId')],
|
||||
SNOWY_THIRD_WECHAT_MINI_CLIENT_SECRET: [required('请输入clientSecret')]
|
||||
}
|
||||
// 验证并提交数据
|
||||
const onSubmit = () => {
|
||||
formRef.value
|
||||
.validate()
|
||||
.then(() => {
|
||||
submitLoading.value = true
|
||||
let submitParam = cloneDeep(formData.value)
|
||||
const param = Object.entries(submitParam).map((item) => {
|
||||
return {
|
||||
configKey: item[0],
|
||||
configValue: item[1]
|
||||
}
|
||||
})
|
||||
configApi
|
||||
.configEditForm(param)
|
||||
.then(() => {})
|
||||
.finally(() => {
|
||||
submitLoading.value = false
|
||||
})
|
||||
})
|
||||
.catch(() => {})
|
||||
}
|
||||
const layout = {
|
||||
labelCol: {
|
||||
span: 24
|
||||
},
|
||||
wrapperCol: {
|
||||
span: 12
|
||||
}
|
||||
}
|
||||
</script>
|
||||
+4
@@ -65,6 +65,9 @@ public enum AuthPlatformEnum {
|
||||
/** 微信 */
|
||||
WECHAT("WECHAT"),
|
||||
|
||||
/** 微信小程序 */
|
||||
WECHAT_MINI("WECHAT_MINI"),
|
||||
|
||||
/** 微博 */
|
||||
WEIBO("WEIBO"),
|
||||
|
||||
@@ -94,6 +97,7 @@ public enum AuthPlatformEnum {
|
||||
YUNZHIJIA.getValue().equals(value) ||
|
||||
QQ.getValue().equals(value) ||
|
||||
WECHAT.getValue().equals(value) ||
|
||||
WECHAT_MINI.getValue().equals(value) ||
|
||||
WEIBO.getValue().equals(value) ||
|
||||
DOUYIN.getValue().equals(value) ||
|
||||
ALIPAY.getValue().equals(value);
|
||||
|
||||
+1
-1
@@ -43,7 +43,7 @@ public class AuthClientFactory {
|
||||
case JWT -> new AuthJwtClient(authSource, authPlatform);
|
||||
case CAS -> new AuthCasClient(authSource, authPlatform);
|
||||
case SAML -> new AuthSamlClient(authSource, authPlatform);
|
||||
case OIDC, IAM, DINGTALK, WORKWECHAT, FEISHU, WELINK, YUNZHIJIA, QQ, WECHAT, WEIBO, DOUYIN, ALIPAY -> new AuthOidcClient(authSource, authPlatform);
|
||||
case OIDC, IAM, DINGTALK, WORKWECHAT, FEISHU, WELINK, YUNZHIJIA, QQ, WECHAT, WECHAT_MINI, WEIBO, DOUYIN, ALIPAY -> new AuthOidcClient(authSource, authPlatform);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
+2
-3
@@ -37,6 +37,7 @@ import vip.xiaonuo.auth.core.protocol.oidc.impl.feishu.AuthOidcFeiShuClient;
|
||||
import vip.xiaonuo.auth.core.protocol.oidc.impl.iam.AuthOidcIamClient;
|
||||
import vip.xiaonuo.auth.core.protocol.oidc.impl.qq.AuthOidcQqClient;
|
||||
import vip.xiaonuo.auth.core.protocol.oidc.impl.wechat.AuthOidcWechatClient;
|
||||
import vip.xiaonuo.auth.core.protocol.oidc.impl.wechatmini.AuthOidcWechatMiniClient;
|
||||
import vip.xiaonuo.auth.core.protocol.oidc.impl.weibo.AuthOidcWeiboClient;
|
||||
import vip.xiaonuo.auth.core.protocol.oidc.impl.welink.AuthOidcWeLinkClient;
|
||||
import vip.xiaonuo.auth.core.protocol.oidc.impl.workwechat.AuthOidcWorkWechatClient;
|
||||
@@ -71,9 +72,6 @@ public class AuthOidcClient extends AuthBaseClient<AuthOidcBaseJson> {
|
||||
if(StrUtil.isBlank(authOidcBaseJson.getClientSecret())) {
|
||||
throw new CommonException("ClientSecret不能为空");
|
||||
}
|
||||
if(StrUtil.isBlank(authOidcBaseJson.getCallbackUrl())) {
|
||||
throw new CommonException("回调地址不能为空");
|
||||
}
|
||||
if(this.getAuthPlatform().equals(AuthPlatformEnum.OIDC.getValue())) {
|
||||
if(StrUtil.isBlank(authOidcBaseJson.getAuthorizeUrl())) {
|
||||
throw new CommonException("认证授权url不能为空");
|
||||
@@ -107,6 +105,7 @@ public class AuthOidcClient extends AuthBaseClient<AuthOidcBaseJson> {
|
||||
case IAM -> authRequest = new AuthOidcIamClient(getAuthBaseJson()).getAuthRequest();
|
||||
case QQ -> authRequest = new AuthOidcQqClient(getAuthBaseJson()).getAuthRequest();
|
||||
case WECHAT -> authRequest = new AuthOidcWechatClient(getAuthBaseJson()).getAuthRequest();
|
||||
case WECHAT_MINI -> authRequest = new AuthOidcWechatMiniClient(getAuthBaseJson()).getAuthRequest();
|
||||
case WEIBO -> authRequest = new AuthOidcWeiboClient(getAuthBaseJson()).getAuthRequest();
|
||||
case DOUYIN -> authRequest = new AuthOidcDouyinClient(getAuthBaseJson()).getAuthRequest();
|
||||
case ALIPAY -> authRequest = new AuthOidcAlipayClient(getAuthBaseJson()).getAuthRequest();
|
||||
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright [2022] [https://www.xiaonuo.vip]
|
||||
*
|
||||
* Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
|
||||
*
|
||||
* 1.请不要删除和修改根目录下的LICENSE文件。
|
||||
* 2.请不要删除和修改Snowy源码头部的版权声明。
|
||||
* 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
|
||||
* 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
|
||||
* 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
|
||||
* 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
|
||||
*/
|
||||
package vip.xiaonuo.auth.core.protocol.oidc.impl.wechatmini;
|
||||
|
||||
import com.xkcoding.http.HttpUtil;
|
||||
import com.xkcoding.http.support.hutool.HutoolImpl;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import me.zhyd.oauth.config.AuthConfig;
|
||||
import me.zhyd.oauth.request.AuthRequest;
|
||||
import me.zhyd.oauth.request.AuthWeChatOpenRequest;
|
||||
import me.zhyd.oauth.request.AuthWechatMiniProgramRequest;
|
||||
import vip.xiaonuo.auth.core.protocol.oidc.AuthOidcBaseJson;
|
||||
|
||||
|
||||
/**
|
||||
* OIDC认证源微信小程序客户端
|
||||
*
|
||||
* @author xuyuxiang
|
||||
* @date 2024/11/8 15:41
|
||||
**/
|
||||
@Slf4j
|
||||
public record AuthOidcWechatMiniClient(AuthOidcBaseJson authOidcBaseJson) {
|
||||
|
||||
public AuthRequest getAuthRequest() {
|
||||
String clientId = authOidcBaseJson.getClientId();
|
||||
String clientSecret = authOidcBaseJson.getClientSecret();
|
||||
HttpUtil.setHttp(new HutoolImpl());
|
||||
return new AuthWechatMiniProgramRequest(AuthConfig.builder()
|
||||
.clientId(clientId)
|
||||
.clientSecret(clientSecret)
|
||||
.ignoreCheckRedirectUri(true)
|
||||
.ignoreCheckState(true)
|
||||
.build());
|
||||
}
|
||||
}
|
||||
+15
@@ -144,6 +144,11 @@ public class AuthThirdServiceImpl extends ServiceImpl<AuthThirdMapper, AuthThird
|
||||
private static final String SNOWY_THIRD_WECHAT_CLIENT_SECRET_KEY = "SNOWY_THIRD_WECHAT_CLIENT_SECRET";
|
||||
private static final String SNOWY_THIRD_WECHAT_REDIRECT_URL_KEY = "SNOWY_THIRD_WECHAT_REDIRECT_URL";
|
||||
|
||||
// 微信小程序
|
||||
private static final String SNOWY_THIRD_WECHAT_MINI_ALLOW_LOGIN_FLAG_KEY = "SNOWY_THIRD_WECHAT_MINI_ALLOW_LOGIN_FLAG";
|
||||
private static final String SNOWY_THIRD_WECHAT_MINI_CLIENT_ID_KEY = "SNOWY_THIRD_WECHAT_MINI_CLIENT_ID";
|
||||
private static final String SNOWY_THIRD_WECHAT_MINI_CLIENT_SECRET_KEY = "SNOWY_THIRD_WECHAT_MINI_CLIENT_SECRET";
|
||||
|
||||
// 钉钉
|
||||
private static final String SNOWY_THIRD_DINGTALK_ALLOW_LOGIN_FLAG_KEY = "SNOWY_THIRD_DINGTALK_ALLOW_LOGIN_FLAG";
|
||||
private static final String SNOWY_THIRD_DINGTALK_CLIENT_ID_KEY = "SNOWY_THIRD_DINGTALK_CLIENT_ID";
|
||||
@@ -515,6 +520,16 @@ public class AuthThirdServiceImpl extends ServiceImpl<AuthThirdMapper, AuthThird
|
||||
.set("clientSecret", devConfigApi.getValueByKey(SNOWY_THIRD_WECHAT_CLIENT_SECRET_KEY))
|
||||
.set("callbackUrl", devConfigApi.getValueByKey(SNOWY_THIRD_WECHAT_REDIRECT_URL_KEY)));
|
||||
}
|
||||
if(platform.equals(AuthPlatformEnum.WECHAT_MINI.getValue())){
|
||||
// 检查是否允许登录
|
||||
if(!Boolean.parseBoolean(devConfigApi.getValueByKey(SNOWY_THIRD_WECHAT_MINI_ALLOW_LOGIN_FLAG_KEY))) {
|
||||
throw new CommonException("微信小程序登录已禁用");
|
||||
}
|
||||
// 微信小程序登录
|
||||
authClient = AuthClientFactory.createClient(platform, JSONUtil.createObj()
|
||||
.set("clientId", devConfigApi.getValueByKey(SNOWY_THIRD_WECHAT_MINI_CLIENT_ID_KEY))
|
||||
.set("clientSecret", devConfigApi.getValueByKey(SNOWY_THIRD_WECHAT_MINI_CLIENT_SECRET_KEY)));
|
||||
}
|
||||
if(platform.equals(AuthPlatformEnum.DINGTALK.getValue())) {
|
||||
// 检查是否允许登录
|
||||
if(!Boolean.parseBoolean(devConfigApi.getValueByKey(SNOWY_THIRD_DINGTALK_ALLOW_LOGIN_FLAG_KEY))) {
|
||||
|
||||
@@ -434,6 +434,9 @@ INSERT INTO `DEV_CONFIG` VALUES ('1908870094824755399', 'SNOWY_THIRD_ALIPAY_CLIE
|
||||
INSERT INTO `DEV_CONFIG` VALUES ('1908870094824755400', 'SNOWY_THIRD_ALIPAY_CLIENT_SECRET', 'ALIPAY客户端SECRET', 'THIRD_ALIPAY', 'ALIPAY客户端SECRET', 273, NULL, 'NOT_DELETE', NULL, NULL, NULL, NULL);
|
||||
INSERT INTO `DEV_CONFIG` VALUES ('1908870094824755401', 'SNOWY_THIRD_ALIPAY_PUBLIC_KEY', 'ALIPAY公钥', 'THIRD_ALIPAY', 'ALIPAY公钥', 274, NULL, 'NOT_DELETE', NULL, NULL, NULL, NULL);
|
||||
INSERT INTO `DEV_CONFIG` VALUES ('1908870094824755402', 'SNOWY_THIRD_ALIPAY_REDIRECT_URL', '重定向URL', 'THIRD_ALIPAY', '重定向URL', 275, NULL, 'NOT_DELETE', NULL, NULL, NULL, NULL);
|
||||
INSERT INTO `DEV_CONFIG` VALUES ('1908870094824755403', 'SNOWY_THIRD_WECHAT_MINI_ALLOW_LOGIN_FLAG', 'false', 'THIRD_WECHAT_MINI', '是否允许WECHAT_MINI登录', 276, NULL, 'NOT_DELETE', NULL, NULL, NULL, NULL);
|
||||
INSERT INTO `DEV_CONFIG` VALUES ('1908870094824755404', 'SNOWY_THIRD_WECHAT_MINI_CLIENT_ID', 'WECHAT_MINI客户端ID', 'THIRD_WECHAT_MINI', 'WECHAT_MINI客户端ID', 277, NULL, 'NOT_DELETE', NULL, NULL, NULL, NULL);
|
||||
INSERT INTO `DEV_CONFIG` VALUES ('1908870094824755405', 'SNOWY_THIRD_WECHAT_MINI_CLIENT_SECRET', 'WECHAT_MINI客户端SECRET', 'THIRD_WECHAT_MINI', 'WECHAT_MINI客户端SECRET', 278, NULL, 'NOT_DELETE', NULL, NULL, NULL, NULL);
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for DEV_DICT
|
||||
|
||||
Reference in New Issue
Block a user