mirror of
https://github.com/certd/certd.git
synced 2026-05-15 12:37:30 +08:00
feat: 彩虹登录支持选择多种登录方式
This commit is contained in:
@@ -85,6 +85,7 @@ export type SysPublicSetting = {
|
||||
type: string;
|
||||
title: string;
|
||||
addonId: number;
|
||||
icon?: string;
|
||||
}
|
||||
>;
|
||||
// 系统通知
|
||||
|
||||
@@ -68,20 +68,23 @@ export async function GetOauthProviders() {
|
||||
});
|
||||
}
|
||||
|
||||
export async function UnbindOauth(type: string) {
|
||||
export async function UnbindOauth(type: string, subtype?: string) {
|
||||
return await request({
|
||||
url: "/oauth/unbind",
|
||||
method: "POST",
|
||||
data: { type },
|
||||
data: {
|
||||
type: subtype ? `${type}:${subtype}` : type,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
export async function OauthBoundUrl(type: string) {
|
||||
export async function OauthBoundUrl(type: string, subtype?: string) {
|
||||
return await request({
|
||||
url: "/oauth/login",
|
||||
method: "POST",
|
||||
data: {
|
||||
type,
|
||||
subtype,
|
||||
forType: "bind",
|
||||
},
|
||||
});
|
||||
|
||||
@@ -78,11 +78,11 @@
|
||||
<a-tag v-else color="red" class="bound-tag1">未绑定</a-tag>
|
||||
</span>
|
||||
</div>
|
||||
<a-button v-if="item.bound" type="primary" danger class="action-btn" @click="unbind(item.name)">
|
||||
<a-button v-if="item.bound" type="primary" danger class="action-btn" @click="unbind(item)">
|
||||
<template #icon><fs-icon icon="ion:unlink-outline" /></template>
|
||||
解绑
|
||||
</a-button>
|
||||
<a-button v-else type="primary" class="action-btn" @click="bind(item.name)">
|
||||
<a-button v-else type="primary" class="action-btn" @click="bind(item)">
|
||||
<template #icon><fs-icon icon="ion:link-outline" /></template>
|
||||
绑定
|
||||
</a-button>
|
||||
@@ -214,7 +214,7 @@ async function loadOauthProviders() {
|
||||
|
||||
const computedOauthBounds = computed(() => {
|
||||
const list = oauthProviders.value.map(item => {
|
||||
const bound = oauthBounds.value.find(bound => bound.type === item.name);
|
||||
const bound = oauthBounds.value.find(bound => bound.type === buildOauthBoundType(item));
|
||||
return {
|
||||
...item,
|
||||
bound,
|
||||
@@ -223,20 +223,24 @@ const computedOauthBounds = computed(() => {
|
||||
return list;
|
||||
});
|
||||
|
||||
async function unbind(type: string) {
|
||||
function buildOauthBoundType(item: any) {
|
||||
return item.subtype ? `${item.name}:${item.subtype}` : item.name;
|
||||
}
|
||||
|
||||
async function unbind(item: any) {
|
||||
Modal.confirm({
|
||||
title: "确认解绑吗?",
|
||||
okText: "确认",
|
||||
okType: "danger",
|
||||
onOk: async () => {
|
||||
await api.UnbindOauth(type);
|
||||
await api.UnbindOauth(item.name, item.subtype);
|
||||
await loadOauthBounds();
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
async function bind(type: string) {
|
||||
const res = await api.OauthBoundUrl(type);
|
||||
async function bind(item: any) {
|
||||
const res = await api.OauthBoundUrl(item.name, item.subtype);
|
||||
const loginUrl = res.loginUrl;
|
||||
window.location.href = loginUrl;
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ import { request } from "/src/api/service";
|
||||
|
||||
const apiPrefix = "/oauth";
|
||||
|
||||
export async function OauthLogin(type: string, forType?: string, from?: string) {
|
||||
export async function OauthLogin(type: string, forType?: string, from?: string, subtype?: string) {
|
||||
return await request({
|
||||
url: apiPrefix + `/login`,
|
||||
method: "post",
|
||||
@@ -10,6 +10,7 @@ export async function OauthLogin(type: string, forType?: string, from?: string)
|
||||
type,
|
||||
forType: forType || "login",
|
||||
from: from || "web",
|
||||
subtype,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
</div>
|
||||
<div class="flex justify-center items-center gap-4 flex-wrap md:flex-nowrap">
|
||||
<passkey-login></passkey-login>
|
||||
<template v-for="item in oauthProviderList" :key="item.type">
|
||||
<div v-if="item.addonId" class="oauth-icon-button pointer" @click="goOauthLogin(item.name)">
|
||||
<template v-for="item in oauthProviderList" :key="buildProviderKey(item)">
|
||||
<div v-if="item.addonId" class="oauth-icon-button pointer" @click="goOauthLogin(item)">
|
||||
<div><fs-icon :icon="item.icon" class="text-blue-600 text-40" /></div>
|
||||
<div class="ellipsis title" :title="item.addonTitle || item.title">{{ item.addonTitle || item.title }}</div>
|
||||
</div>
|
||||
@@ -22,7 +22,17 @@ import { useSettingStore } from "/@/store/settings";
|
||||
import { useRoute } from "vue-router";
|
||||
import PasskeyLogin from "../login/passkey-login.vue";
|
||||
|
||||
const oauthProviderList = ref([]);
|
||||
type OauthProviderItem = {
|
||||
name: string;
|
||||
type?: string;
|
||||
subtype?: string;
|
||||
title: string;
|
||||
addonTitle?: string;
|
||||
icon: string;
|
||||
addonId?: number;
|
||||
};
|
||||
|
||||
const oauthProviderList = ref<OauthProviderItem[]>([]);
|
||||
const props = defineProps<{
|
||||
oauthOnly?: boolean;
|
||||
}>();
|
||||
@@ -42,15 +52,19 @@ onMounted(async () => {
|
||||
if (settingStore.sysPublic.oauthAutoRedirect && queryOauthOnly !== "false") {
|
||||
const firstOauth = oauthProviderList.value.find(item => item.addonId > 0);
|
||||
if (firstOauth) {
|
||||
goOauthLogin(firstOauth.name);
|
||||
goOauthLogin(firstOauth);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
async function goOauthLogin(type: string) {
|
||||
function buildProviderKey(item: OauthProviderItem) {
|
||||
return `${item.name}:${item.subtype || ""}`;
|
||||
}
|
||||
|
||||
async function goOauthLogin(item: OauthProviderItem) {
|
||||
//获取第三方登录URL
|
||||
const from = "web";
|
||||
const res = await api.OauthLogin(type, from);
|
||||
const res = await api.OauthLogin(item.name, "login", from, item.subtype);
|
||||
const loginUrl = res.loginUrl;
|
||||
window.location.href = loginUrl;
|
||||
}
|
||||
|
||||
@@ -114,7 +114,7 @@ export async function GetSmsTypeDefine(type: string) {
|
||||
|
||||
export async function GetOauthProviders() {
|
||||
return await request({
|
||||
url: "/oauth/providers",
|
||||
url: apiPrefix + "/oauth/providers",
|
||||
method: "post",
|
||||
});
|
||||
}
|
||||
|
||||
@@ -109,6 +109,7 @@ const formState = reactive<Partial<SysSettings>>({
|
||||
const oauthProviders = ref([]);
|
||||
async function loadOauthProviders() {
|
||||
oauthProviders.value = await api.GetOauthProviders();
|
||||
mergeOauthProviderSettings();
|
||||
}
|
||||
|
||||
const bindDomain = computed(() => {
|
||||
@@ -164,6 +165,16 @@ const onFinish = async (form: any) => {
|
||||
function buildCallbackUrl(type: string) {
|
||||
return `${window.location.origin}/api/oauth/callback/${type}`;
|
||||
}
|
||||
|
||||
function mergeOauthProviderSettings() {
|
||||
const savedProviders = formState.public?.oauthProviders || {};
|
||||
for (const item of oauthProviders.value) {
|
||||
const saved = savedProviders[item.name];
|
||||
if (saved) {
|
||||
item.addonId = saved.addonId;
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="less">
|
||||
.sys-settings-oauth {
|
||||
|
||||
Reference in New Issue
Block a user