refactor: 重构oauth相关代码 添加新的默认oauth登录方式
This commit is contained in:
parent
db955071d7
commit
6c942418b4
@ -6,6 +6,7 @@ import type { TenantResp } from '#/api';
|
||||
import { computed, onMounted, ref, useTemplateRef } from 'vue';
|
||||
|
||||
import { AuthenticationCodeLogin, z } from '@vben/common-ui';
|
||||
import { DEFAULT_TENANT_ID } from '@vben/constants';
|
||||
import { $t } from '@vben/locales';
|
||||
|
||||
import { Alert, message } from 'ant-design-vue';
|
||||
@ -50,7 +51,7 @@ const formSchema = computed((): VbenFormSchema[] => {
|
||||
})),
|
||||
placeholder: $t('authentication.selectAccount'),
|
||||
},
|
||||
defaultValue: '000000',
|
||||
defaultValue: DEFAULT_TENANT_ID,
|
||||
dependencies: {
|
||||
if: () => tenantInfo.value.tenantEnabled,
|
||||
triggerFields: [''],
|
||||
|
@ -7,6 +7,7 @@ import type { CaptchaResponse } from '#/api/core/captcha';
|
||||
import { computed, onMounted, ref, useTemplateRef } from 'vue';
|
||||
|
||||
import { AuthenticationLogin, z } from '@vben/common-ui';
|
||||
import { DEFAULT_TENANT_ID } from '@vben/constants';
|
||||
import { $t } from '@vben/locales';
|
||||
|
||||
import { omit } from 'lodash-es';
|
||||
@ -15,6 +16,7 @@ import { tenantList } from '#/api';
|
||||
import { captchaImage } from '#/api/core/captcha';
|
||||
import { useAuthStore } from '#/store';
|
||||
|
||||
import { useLoginTenantId } from '../oauth-common';
|
||||
import OAuthLogin from './oauth-login.vue';
|
||||
|
||||
defineOptions({ name: 'Login' });
|
||||
@ -56,6 +58,8 @@ onMounted(async () => {
|
||||
await Promise.all([loadCaptcha(), loadTenant()]);
|
||||
});
|
||||
|
||||
const { loginTenantId } = useLoginTenantId();
|
||||
|
||||
const formSchema = computed((): VbenFormSchema[] => {
|
||||
return [
|
||||
{
|
||||
@ -69,16 +73,13 @@ const formSchema = computed((): VbenFormSchema[] => {
|
||||
})),
|
||||
placeholder: $t('authentication.selectAccount'),
|
||||
},
|
||||
defaultValue: '000000',
|
||||
defaultValue: DEFAULT_TENANT_ID,
|
||||
dependencies: {
|
||||
if: () => tenantInfo.value.tenantEnabled,
|
||||
// 这里大致上是watch的一个效果
|
||||
componentProps: (model) => {
|
||||
localStorage.setItem(
|
||||
'__oauth_tenant_id',
|
||||
model?.tenantId ?? '000000',
|
||||
);
|
||||
return {};
|
||||
// 可以把这里当做watch
|
||||
trigger: (model) => {
|
||||
// 给oauth登录使用
|
||||
loginTenantId.value = model?.tenantId ?? DEFAULT_TENANT_ID;
|
||||
},
|
||||
triggerFields: ['', 'tenantId'],
|
||||
},
|
||||
|
@ -3,21 +3,16 @@ import { $t } from '@vben/locales';
|
||||
|
||||
import { Col, Row, Tooltip } from 'ant-design-vue';
|
||||
|
||||
import { accountBindList } from '../oauth-common';
|
||||
import { accountBindList, handleAuthBinding } from '../oauth-common';
|
||||
|
||||
defineOptions({
|
||||
name: 'OAuthLogin',
|
||||
});
|
||||
|
||||
/**
|
||||
* 有action方法才会显示
|
||||
*/
|
||||
const clientList = accountBindList.filter((item) => item.action);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="w-full sm:mx-auto md:max-w-md">
|
||||
<div class="mt-4 flex items-center justify-between">
|
||||
<div class="my-4 flex items-center justify-between">
|
||||
<span class="border-input w-[35%] border-b dark:border-gray-600"></span>
|
||||
<span class="text-muted-foreground text-center text-xs uppercase">
|
||||
{{ $t('authentication.thirdPartyLogin') }}
|
||||
@ -26,15 +21,20 @@ const clientList = accountBindList.filter((item) => item.action);
|
||||
</div>
|
||||
<Row class="enter-x flex items-center justify-evenly">
|
||||
<!-- todo 这里在点击登录时要disabled -->
|
||||
<Col v-for="item in clientList" :key="item.key" :span="4" class="my-2">
|
||||
<Col
|
||||
v-for="item in accountBindList"
|
||||
:key="item.source"
|
||||
:span="4"
|
||||
class="my-2"
|
||||
>
|
||||
<Tooltip :title="`${item.title}登录`">
|
||||
<span class="flex cursor-pointer items-center justify-center">
|
||||
<component
|
||||
:is="item.avatar"
|
||||
v-if="item.avatar"
|
||||
:style="{ color: item.color }"
|
||||
:is="item.avatar"
|
||||
:style="item?.style ?? {}"
|
||||
class="size-[24px]"
|
||||
@click="item.action"
|
||||
@click="handleAuthBinding(item.source)"
|
||||
/>
|
||||
</span>
|
||||
</Tooltip>
|
||||
|
@ -1,104 +1,103 @@
|
||||
import type { Component } from 'vue';
|
||||
import type { Component, CSSProperties } from 'vue';
|
||||
|
||||
import { ref } from 'vue';
|
||||
|
||||
import { DEFAULT_TENANT_ID } from '@vben/constants';
|
||||
import {
|
||||
AlipayIcon,
|
||||
DingdingIcon,
|
||||
GiteeIcon,
|
||||
GithubOAuthIcon,
|
||||
TaobaoIcon,
|
||||
SvgMaxKeyIcon,
|
||||
SvgTopiamIcon,
|
||||
SvgWechatIcon,
|
||||
} from '@vben/icons';
|
||||
|
||||
import { createGlobalState } from '@vueuse/core';
|
||||
|
||||
import { authBinding } from '#/api/core/auth';
|
||||
|
||||
/**
|
||||
* @description: 菜单
|
||||
* @param key key
|
||||
* @description: oauth登录
|
||||
* @param title 标题
|
||||
* @param description 描述
|
||||
* @param extra 按钮文字
|
||||
* @param avatar 图标
|
||||
* @param color 图标颜色可直接写英文颜色/hex
|
||||
*/
|
||||
export interface ListItem {
|
||||
key: string;
|
||||
title: string;
|
||||
description: string;
|
||||
extra?: string;
|
||||
avatar?: Component;
|
||||
color?: string;
|
||||
style?: CSSProperties;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description: 绑定账号
|
||||
* @param source 来源 如gitee github 与后端的social-callback?source=xxx对应
|
||||
* @param bound 是否已经绑定
|
||||
* @param action 账号绑定回调
|
||||
*/
|
||||
export interface BindItem extends ListItem {
|
||||
source: string;
|
||||
bound?: boolean;
|
||||
action?: (source: string) => Promise<any>;
|
||||
}
|
||||
|
||||
/**
|
||||
* todo tenantId
|
||||
* 绑定授权从userStore.userInfo获取
|
||||
* 登录从localStorage获取
|
||||
* 这里存储登录页的tenantId 由于个人中心也会用到 需要共享
|
||||
* 所以使用`createGlobalState`
|
||||
* @see https://vueuse.org/shared/createGlobalState/
|
||||
*/
|
||||
export const useLoginTenantId = createGlobalState(() => {
|
||||
const loginTenantId = ref(DEFAULT_TENANT_ID);
|
||||
|
||||
return {
|
||||
loginTenantId,
|
||||
};
|
||||
});
|
||||
|
||||
/**
|
||||
* 绑定授权
|
||||
* @param source
|
||||
*/
|
||||
async function handleAuthBinding(source: string) {
|
||||
const tenantId = localStorage.getItem('__oauth_tenant_id') ?? '000000';
|
||||
export async function handleAuthBinding(source: string) {
|
||||
const { loginTenantId } = useLoginTenantId();
|
||||
// 这里返回打开授权页面的链接
|
||||
const href = await authBinding(source, tenantId);
|
||||
const href = await authBinding(source, loginTenantId.value);
|
||||
window.location.href = href;
|
||||
}
|
||||
|
||||
/**
|
||||
* 账号绑定 list
|
||||
* 添加账号绑定只需要在这里增加即可
|
||||
* 添加过的项目会在个人主页-绑定账号中显示
|
||||
* action不为空的会在登录页显示
|
||||
*/
|
||||
export const accountBindList: BindItem[] = [
|
||||
{
|
||||
avatar: TaobaoIcon,
|
||||
color: '#ff4000',
|
||||
description: '绑定淘宝账号',
|
||||
key: '1',
|
||||
source: 'taobao',
|
||||
title: '淘宝',
|
||||
},
|
||||
{
|
||||
avatar: AlipayIcon,
|
||||
color: '#2eabff',
|
||||
description: '绑定支付宝账号',
|
||||
key: '2',
|
||||
source: 'alipay',
|
||||
title: '支付宝',
|
||||
},
|
||||
{
|
||||
avatar: DingdingIcon,
|
||||
color: '#2eabff',
|
||||
description: '绑定钉钉账号',
|
||||
key: '3',
|
||||
source: 'ding',
|
||||
title: '钉钉',
|
||||
},
|
||||
{
|
||||
action: () => handleAuthBinding('gitee'),
|
||||
avatar: GiteeIcon,
|
||||
color: '#c71d23',
|
||||
description: '绑定GITEE账号',
|
||||
key: '4',
|
||||
description: '绑定Gitee账号',
|
||||
source: 'gitee',
|
||||
title: 'GITEE',
|
||||
title: 'Gitee',
|
||||
style: { color: '#c71d23' },
|
||||
},
|
||||
{
|
||||
action: () => handleAuthBinding('github'),
|
||||
avatar: GithubOAuthIcon,
|
||||
color: '',
|
||||
description: '绑定GITHUB账号',
|
||||
key: '5',
|
||||
description: '绑定Github账号',
|
||||
source: 'github',
|
||||
title: 'GITHUB',
|
||||
title: 'Github',
|
||||
},
|
||||
{
|
||||
avatar: SvgMaxKeyIcon,
|
||||
description: '绑定MaxKey账号',
|
||||
source: 'maxkey',
|
||||
title: 'MaxKey',
|
||||
style: { verticalAlign: 'middle' },
|
||||
},
|
||||
{
|
||||
avatar: SvgTopiamIcon,
|
||||
description: '绑定topiam账号',
|
||||
source: 'topiam',
|
||||
title: 'Topiam',
|
||||
},
|
||||
{
|
||||
avatar: SvgWechatIcon,
|
||||
description: '绑定wechat账号',
|
||||
source: 'wechat',
|
||||
title: 'Wechat',
|
||||
},
|
||||
];
|
||||
|
@ -7,27 +7,12 @@ import { computed, ref, unref } from 'vue';
|
||||
|
||||
import { useVbenVxeGrid } from '@vben/plugins/vxe-table';
|
||||
|
||||
import {
|
||||
Alert,
|
||||
Avatar,
|
||||
Card,
|
||||
List,
|
||||
ListItem,
|
||||
message,
|
||||
Modal,
|
||||
} from 'ant-design-vue';
|
||||
import { Alert, Avatar, Card, List, ListItem, Modal } from 'ant-design-vue';
|
||||
|
||||
import { authUnbinding } from '#/api';
|
||||
import { socialList } from '#/api/system/social';
|
||||
|
||||
import { accountBindList } from '../../oauth-common';
|
||||
|
||||
/**
|
||||
* 没有传递action事件则不支持绑定 弹出默认提示
|
||||
*/
|
||||
function defaultTip(title: string) {
|
||||
message.info({ content: `暂不支持绑定${title}` });
|
||||
}
|
||||
import { accountBindList, handleAuthBinding } from '../../oauth-common';
|
||||
|
||||
function buttonText(item: BindItem) {
|
||||
return item.bound ? '已绑定' : '绑定';
|
||||
@ -151,7 +136,7 @@ function handleUnbind(record: Record<string, any>) {
|
||||
<component
|
||||
:is="item.avatar"
|
||||
v-if="item.avatar"
|
||||
:style="{ color: item.color }"
|
||||
:style="item?.style ?? {}"
|
||||
class="size-[40px]"
|
||||
/>
|
||||
</div>
|
||||
@ -170,9 +155,7 @@ function handleUnbind(record: Record<string, any>) {
|
||||
:disabled="item.bound"
|
||||
size="small"
|
||||
type="link"
|
||||
@click="
|
||||
item.action ? item.action() : defaultTip(item.title)
|
||||
"
|
||||
@click="handleAuthBinding(item.source)"
|
||||
>
|
||||
{{ buttonText(item) }}
|
||||
</a-button>
|
||||
@ -191,10 +174,6 @@ function handleUnbind(record: Record<string, any>) {
|
||||
</span>
|
||||
中accountBindList按模板添加
|
||||
</p>
|
||||
<p>
|
||||
添加对应模板后会在此处显示绑定, 但只有
|
||||
<span class="font-bold">实现了action才能在登录页显示</span>
|
||||
</p>
|
||||
</template>
|
||||
</Alert>
|
||||
</div>
|
||||
|
@ -4,7 +4,7 @@ import type { AuthApi } from '#/api';
|
||||
import { onMounted } from 'vue';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
|
||||
import { DEFAULT_HOME_PATH } from '@vben/constants';
|
||||
import { DEFAULT_HOME_PATH, DEFAULT_TENANT_ID } from '@vben/constants';
|
||||
import { useAccessStore } from '@vben/stores';
|
||||
|
||||
import { message } from 'ant-design-vue';
|
||||
@ -22,7 +22,7 @@ const stateJson = JSON.parse(atob(state));
|
||||
// 来源
|
||||
const source = route.query.source as string;
|
||||
// 租户ID
|
||||
const defaultTenantId = '000000';
|
||||
const defaultTenantId = DEFAULT_TENANT_ID;
|
||||
const tenantId = (stateJson.tenantId as string) ?? defaultTenantId;
|
||||
const domain = stateJson.domain as string;
|
||||
|
||||
@ -44,7 +44,7 @@ onMounted(async () => {
|
||||
try {
|
||||
// 已经实现的平台
|
||||
const currentClient = accountBindList.find(
|
||||
(item) => item.source === source && item.action,
|
||||
(item) => item.source === source,
|
||||
);
|
||||
if (!currentClient) {
|
||||
message.error({ content: `未找到${source}平台` });
|
||||
|
12
packages/icons/src/svg/icons/max-key.svg
Normal file
12
packages/icons/src/svg/icons/max-key.svg
Normal file
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 10 KiB |
29
packages/icons/src/svg/icons/topiam.svg
Normal file
29
packages/icons/src/svg/icons/topiam.svg
Normal file
@ -0,0 +1,29 @@
|
||||
<svg width="200" height="200" viewBox="0 0 200 200" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0_446_540)">
|
||||
<path d="M113.069 160.072C103.717 170.743 93.0453 180.216 81.5345 188.609C61.5105 174.46 44.3642 156.595 30.9349 135.971C23.5009 124.46 17.2659 112.11 12.4697 99.0407C9.592 91.3668 7.19392 83.3332 5.27545 75.2996C2.03803 61.3907 0.359375 47.0022 0.359375 32.1341C0.359375 30.6953 0.359375 29.1365 0.359375 27.6977C6.35459 23.9806 12.7095 20.7432 19.0644 17.7456C20.7431 32.1341 24.1004 46.043 28.8966 59.3524C31.6544 66.9063 34.7719 74.3404 38.4889 81.4147C44.604 93.5251 52.0381 104.796 60.4314 115.228C75.1796 133.093 92.9254 148.321 113.069 160.072Z" fill="url(#paint0_linear_446_540)"/>
|
||||
<path d="M196.643 67.6256C195.084 76.3786 192.926 84.8918 190.168 93.1652C178.897 91.1269 167.266 90.0477 155.276 90.0477C154.197 90.0477 153.118 90.0477 152.039 90.0477C126.859 90.4074 102.878 95.6832 80.9352 105.036C72.302 94.8439 64.868 83.453 58.9927 71.3427C81.6546 61.8702 106.475 56.7144 132.614 56.7144C141.487 56.7144 150.24 57.3139 158.753 58.5129C171.823 60.1916 184.533 63.3091 196.643 67.6256Z" fill="url(#paint1_linear_446_540)"/>
|
||||
<path d="M199.64 34.0528C199.64 39.2087 199.401 44.3646 199.041 49.4005C186.691 44.1247 173.621 40.048 160.072 37.53C148.321 35.2518 136.211 34.0528 123.981 34.0528C97.7218 34.0528 72.6619 39.3286 49.88 48.9209C42.6858 51.9185 35.7313 55.3958 29.0167 59.2327C24.2205 46.0432 20.8632 32.0144 19.1846 17.6259C26.6186 14.1487 34.2925 11.271 42.2062 8.75301C60.3117 3.11751 79.4964 0 99.4005 0C119.904 0 139.568 3.23741 158.153 9.11272C172.782 13.789 186.691 20.2638 199.52 28.1775C199.64 30.2159 199.64 32.1343 199.64 34.0528Z" fill="url(#paint2_linear_446_540)"/>
|
||||
<path d="M190.168 93.2855C182.494 116.547 170.384 137.65 154.796 155.875C149.76 161.751 144.364 167.386 138.609 172.542C126.858 183.214 113.789 192.446 99.7601 200C93.4052 196.523 87.41 192.686 81.5347 188.609C93.0455 180.336 103.717 170.744 113.069 160.072C117.866 154.676 122.302 148.921 126.499 143.046C137.65 127.098 146.403 109.233 152.158 90.1679C153.237 90.1679 154.316 90.1679 155.396 90.1679C167.146 90.048 178.777 91.1272 190.168 93.2855Z" fill="url(#paint3_linear_446_540)"/>
|
||||
</g>
|
||||
<defs>
|
||||
<linearGradient id="paint0_linear_446_540" x1="15.8569" y1="27.5782" x2="86.4712" y2="182.06" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#57A4F7"/>
|
||||
<stop offset="1" stop-color="#2158F9"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="paint1_linear_446_540" x1="58.9501" y1="80.8427" x2="196.648" y2="80.8427" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#2158F9"/>
|
||||
<stop offset="1" stop-color="#33E1E5"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="paint2_linear_446_540" x1="19.1564" y1="29.6353" x2="199.647" y2="29.6353" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#255DF9"/>
|
||||
<stop offset="1" stop-color="#7C35BA"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="paint3_linear_446_540" x1="95.3808" y1="192.567" x2="174.674" y2="97.4815" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#54A0F7"/>
|
||||
<stop offset="1" stop-color="#2158F9"/>
|
||||
</linearGradient>
|
||||
<clipPath id="clip0_446_540">
|
||||
<rect width="200" height="200" fill="white"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
After Width: | Height: | Size: 3.1 KiB |
1
packages/icons/src/svg/icons/wechat.svg
Normal file
1
packages/icons/src/svg/icons/wechat.svg
Normal file
@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1742660391897" class="icon" viewBox="0 0 1170 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3162" xmlns:xlink="http://www.w3.org/1999/xlink" width="292.5" height="256"><path d="M331.429 263.429q0-23.429-14.286-37.715t-37.714-14.285q-24.572 0-43.429 14.571t-18.857 37.429q0 22.285 18.857 36.857t43.429 14.571q23.428 0 37.714-14t14.286-37.428zM756 553.143q0-16-14.571-28.572T704 512q-15.429 0-28.286 12.857t-12.857 28.286q0 16 12.857 28.857T704 594.857q22.857 0 37.429-12.571T756 553.143zM621.143 263.429q0-23.429-14-37.715t-37.429-14.285q-24.571 0-43.428 14.571t-18.857 37.429q0 22.285 18.857 36.857t43.428 14.571q23.429 0 37.429-14t14-37.428zM984 553.143q0-16-14.857-28.572T932 512q-15.429 0-28.286 12.857t-12.857 28.286q0 16 12.857 28.857T932 594.857q22.286 0 37.143-12.571T984 553.143zM832 326.286Q814.286 324 792 324q-96.571 0-177.714 44T486.57 487.143 440 651.429q0 44.571 13.143 86.857-20 1.714-38.857 1.714-14.857 0-28.572-0.857t-31.428-3.714-25.429-4-31.143-6-28.571-6L124.57 792l41.143-124.571Q0 551.429 0 387.429q0-96.572 55.714-177.715T206.571 82t207.715-46.571q100.571 0 190 37.714T754 177.429t78 148.857z m338.286 320.571q0 66.857-39.143 127.714t-106 110.572l31.428 103.428-113.714-62.285q-85.714 21.143-124.571 21.143-96.572 0-177.715-40.286T512.857 797.714t-46.571-150.857T512.857 496t127.714-109.429 177.715-40.285q92 0 173.143 40.285t130 109.715 48.857 150.571z" fill="#0e932e" p-id="3163"></path></svg>
|
After Width: | Height: | Size: 1.5 KiB |
@ -11,6 +11,9 @@ const SvgCardIcon = createIconifyIcon('svg:card');
|
||||
const SvgBellIcon = createIconifyIcon('svg:bell');
|
||||
const SvgCakeIcon = createIconifyIcon('svg:cake');
|
||||
const SvgAntdvLogoIcon = createIconifyIcon('svg:antdv-logo');
|
||||
const SvgMaxKeyIcon = createIconifyIcon('svg:max-key');
|
||||
const SvgTopiamIcon = createIconifyIcon('svg:topiam');
|
||||
const SvgWechatIcon = createIconifyIcon('svg:wechat');
|
||||
|
||||
export {
|
||||
SvgAntdvLogoIcon,
|
||||
@ -22,6 +25,9 @@ export {
|
||||
SvgCakeIcon,
|
||||
SvgCardIcon,
|
||||
SvgDownloadIcon,
|
||||
SvgMaxKeyIcon,
|
||||
SvgTopiamIcon,
|
||||
SvgWechatIcon,
|
||||
};
|
||||
|
||||
export { default as SvgMessageUrl } from './icons/message.svg';
|
||||
|
Loading…
Reference in New Issue
Block a user