perf: update auth intergration

This commit is contained in:
ibuler
2025-05-09 17:19:51 +08:00
committed by 老广
parent b5ea5b21fd
commit 41ec908f37
5 changed files with 135 additions and 228 deletions

View File

@@ -2,6 +2,7 @@ import defaultSettings from '@/settings'
import { getPublicSettings } from '@/api/settings'
import { changeElementColor, changeThemeColors } from '@/utils/theme/index'
import { changeMenuColor } from '@/utils/theme/color'
import request from '@/utils/request'
const { showSettings, fixedHeader, sidebarLogo, tagsView } = defaultSettings
@@ -12,6 +13,7 @@ const state = {
tagsView: tagsView,
publicSettings: {},
hasValidLicense: false,
authMethods: {},
themeColors: JSON.parse(localStorage.getItem('themeColors')) || {}
}
@@ -78,6 +80,34 @@ const actions = {
changeMenuColor(themeColors)
changeElementColor(themeColors)
commit('setTheme', themeColors)
},
updateAuthItemStatus({ commit }, payload) {
const [key, value] = payload
return new Promise((resolve, reject) => {
const url = '/api/v1/settings/setting/?category=auth'
const data = { [key]: value }
request.patch(url, data).then(res => {
state.authMethods[key] = value
resolve(res)
}).catch(error => {
reject(error)
})
})
},
getAuthMethods({ commit, state }) {
return new Promise((resolve, reject) => {
if (state.authMethods && Object.keys(state.authMethods).length > 0) {
resolve(state.authMethods)
} else {
const url = '/api/v1/settings/setting/?category=auth'
request.get(url).then(res => {
state.authMethods = res
resolve(res)
}).catch(error => {
reject(error)
})
}
})
}
}

View File

@@ -1,33 +1,32 @@
<template>
<div class="auth-container">
<IBox class="auth-box-wrapper">
<IBox :title="$tc('AuthIntegration')" class="auth-box-wrapper">
<el-row :gutter="20">
<AuthItem
<AuthMethod
v-for="item in authItems"
:key="item.title"
v-bind="item"
@update:enabled="updateAuthItemStatus"
/>
</el-row>
</IBox>
<IBox>
<IBox :title="$tc('BasicSettings')" class="auth-box-wrapper">
<GenericCreateUpdateForm v-bind="$data" />
</IBox>
</div>
</template>
<script>
import AuthItem from './AuthItem.vue'
import AuthMethod from './components/AuthMethod.vue'
import IBox from '@/components/Common/IBox'
import { getAuthItem, setAuthItem } from './const'
import { getAuthItems } from './const'
import { GenericCreateUpdateForm } from '@/layout/components'
import { mapState } from 'vuex'
export default {
components: {
IBox,
GenericCreateUpdateForm,
AuthItem
AuthMethod,
GenericCreateUpdateForm
},
data() {
return {
@@ -51,23 +50,37 @@ export default {
}
}
},
computed: {
...mapState({
authMethodsSetting: state => state.settings.authMethods
})
},
mounted() {
this.authItems = getAuthItem(this)
this.$store.dispatch('settings/getAuthMethods')
this.initAuthItems()
},
methods: {
updateAuthItemStatus(value, key) {
setAuthItem(value, key)
this.$nextTick(() => {
this.authItems = getAuthItem(this)
this.$emit('update:tabs', key, value)
async initAuthItems() {
let authItems = await getAuthItems(this)
authItems = authItems.map(item => {
return {
...item,
enabled: this.authMethodsSetting[item.authKey]
}
})
this.authItems = authItems.sort((a, b) => {
if (a.enabled !== b.enabled) {
return a.enabled ? -1 : 1
}
return a.title.localeCompare(b.title)
})
}
}
}
</script>
<style scoped lang="scss">
<style lang="scss" scoped>
.auth-container {
width: 100%;

View File

@@ -1,10 +1,10 @@
<template>
<el-col :span="8" :xs="24" :sm="12" :md="8" :lg="6" :xl="4" class="auth-item-col">
<el-card ref="card" shadow="hover" class="auth-card">
<el-col :lg="6" :md="8" :sm="12" :span="8" :xl="4" :xs="24" class="auth-item-col">
<el-card ref="card" class="auth-card" shadow="hover">
<div slot="header" class="auth-item-header">
<div class="auth-item-header-left">
<img :src="logo" alt="auth-logo" class="auth-logo">
<div class="auth-item-header-title" :title="title">{{ title }}</div>
<div :title="title" class="auth-item-header-title">{{ title }}</div>
</div>
<div class="auth-item-actions">
<el-switch
@@ -54,20 +54,15 @@ export default {
this.isEnabled = newVal
}
},
mounted() {
const card = this.$refs.card
this.cardBody = card.$el.querySelector('.el-card__body')
this.cardBody.style.display = 'none'
},
methods: {
onChangeStatus(value) {
this.$emit('update:enabled', value, this.authKey)
this.$store.dispatch('settings/updateAuthItemStatus', [this.authKey, value])
}
}
}
</script>
<style scoped lang="scss">
<style lang="scss" scoped>
.auth-item-col {
margin: 10px 0;
padding: 0 10px;
@@ -81,6 +76,7 @@ export default {
display: flex;
align-items: center;
justify-content: space-between;
padding: 5px;
.auth-item-header-left {
display: flex;
@@ -109,8 +105,8 @@ export default {
}
}
::v-deep(.el-card__body) {
display: none !important;
::v-deep .el-card__body {
display: none;
}
}
}

View File

@@ -1,5 +1,6 @@
import store from '@/store'
import { Select2 } from '@/components/Form/FormFields'
import i18n from '@/i18n/i18n'
import { ObjectLocalStorage } from '@/utils/common'
export const authLocalStorage = new ObjectLocalStorage('auth')
@@ -22,136 +23,108 @@ export function getOrgSelect2Meta() {
}
}
export const getAuthItem = (vm) => {
const storageItems = authLocalStorage.get('authItems')
if (storageItems) {
return storageItems
}
const ldapHABackends = [
export function getAuthItems() {
const xpackBackends = [
{
name: 'LdapHA',
logo: require('@/assets/img/auth/ldap_logo.png'),
title: vm.$t('LDAP HA'),
title: i18n.t('LDAP HA'),
authKey: 'AUTH_LDAP_HA',
description: '',
enabled: false
}
]
const extraBackends = [
description: ''
},
{
name: 'OIDC',
title: i18n.t('OIDC'),
logo: require('@/assets/img/auth/oidc_logo.png'),
title: vm.$t('OIDC'),
authKey: 'AUTH_OPENID',
description: '',
enabled: false
description: ''
},
{
name: 'SAML2',
logo: require('@/assets/img/auth/saml2_logo.png'),
title: vm.$t('SAML2'),
title: i18n.t('SAML2'),
authKey: 'AUTH_SAML2',
description: '',
enabled: false
description: ''
},
{
name: 'OAUTH2',
logo: require('@/assets/img/auth/oauth2_logo.png'),
title: vm.$t('OAuth2'),
title: i18n.t('OAuth2'),
authKey: 'AUTH_OAUTH2',
description: '',
enabled: false
description: ''
},
{
name: 'WeCom',
logo: require('@/assets/img/auth/wecom_logo.png'),
title: vm.$t('WeCom'),
title: i18n.t('WeCom'),
authKey: 'AUTH_WECOM',
description: '',
enabled: false
description: ''
},
{
name: 'DingTalk',
logo: require('@/assets/img/auth/dingtalk_logo.webp'),
title: vm.$t('DingTalk'),
title: i18n.t('DingTalk'),
authKey: 'AUTH_DINGTALK',
description: '',
enabled: false
description: ''
},
{
name: 'FeiShu',
logo: require('@/assets/img/auth/feishu_logo.png'),
title: vm.$t('FeiShu'),
title: i18n.t('FeiShu'),
authKey: 'AUTH_FEISHU',
description: '',
enabled: false
description: ''
},
{
name: 'Lark',
logo: require('@/assets/img/auth/lark_logo.png'),
title: vm.$t('Lark'),
title: i18n.t('Lark'),
authKey: 'AUTH_LARK',
description: '',
enabled: false
description: ''
},
{
name: 'Slack',
logo: require('@/assets/img/auth/slack_logo.png'),
title: vm.$t('Slack'),
title: i18n.t('Slack'),
authKey: 'AUTH_SLACK',
description: '',
enabled: false
description: ''
},
{
name: 'Radius',
logo: require('@/assets/img/auth/radius_logo.png'),
title: vm.$t('Radius'),
title: i18n.t('Radius'),
authKey: 'AUTH_RADIUS',
description: '',
enabled: false
description: ''
}
]
const authItems = [
{
name: 'LDAP',
logo: require('@/assets/img/auth/ldap_logo.png'),
title: vm.$t('Ldap'),
title: i18n.t('Ldap'),
authKey: 'AUTH_LDAP',
description: '',
enabled: true
description: ''
},
{
name: 'CAS',
logo: require('@/assets/img/auth/cas_logo.png'),
title: vm.$t('CAS'),
title: i18n.t('CAS'),
authKey: 'AUTH_CAS',
description: '',
enabled: true
description: ''
},
{
name: 'Passkey',
logo: require('@/assets/img/auth/passkey_logo.png'),
title: vm.$t('Passkey'),
title: i18n.t('Passkey'),
authKey: 'AUTH_PASSKEY',
description: '',
enabled: true
description: ''
}
]
if (store.getters.hasValidLicense) {
// 把 AUTH_LDAP_HA 加到 authItems 中的 AUTH_LDAP 后面
const ldapIndex = authItems.findIndex(item => item.authKey === 'AUTH_LDAP')
if (ldapIndex !== -1) {
authItems.splice(ldapIndex + 1, 0, ...ldapHABackends)
}
authItems.push(...extraBackends)
authItems.push(...xpackBackends)
}
authLocalStorage.set('authItems', authItems)
return authItems
}
export const setAuthItem = (value, authKey) => {
const authItems = authLocalStorage.get('authItems')
const authItem = authItems.find(item => item.authKey === authKey)
if (authItem) {
authItem.enabled = value
authLocalStorage.set('authItems', authItems)
}
}

View File

@@ -1,7 +1,7 @@
<template>
<TabPage v-if="!loading" :active-menu.sync="activeMenu" :submenu="submenu">
<TabPage v-if="!loading" :active-menu.sync="activeMenu" :submenu="menu">
<keep-alive>
<component :is="activeMenu" @update:tabs="updateActiveMenu" />
<component :is="activeMenu" />
</keep-alive>
</TabPage>
</template>
@@ -24,7 +24,8 @@ import SAML2 from './SAML2'
import OAuth2 from './OAuth2'
import Passkey from './Passkey.vue'
import Slack from './Slack.vue'
import { authLocalStorage } from './const'
import { getAuthItems } from './const'
import { mapState } from 'vuex'
export default {
components: {
@@ -50,141 +51,35 @@ export default {
return {
loading: true,
activeMenu: 'Basic',
defaultBackends: [
{
title: this.$t('Ldap'),
name: 'LDAP',
key: 'AUTH_LDAP'
},
{
title: this.$t('CAS'),
name: 'CAS',
key: 'AUTH_CAS'
},
{
title: this.$t('Passkey'),
name: 'Passkey',
key: 'AUTH_PASSKEY'
}
],
extraBackends: [
{
title: this.$t('OIDC'),
name: 'OIDC',
key: 'AUTH_OPENID'
},
{
title: this.$t('SAML2'),
name: 'SAML2',
key: 'AUTH_SAML2'
},
{
title: this.$t('OAuth2'),
name: 'OAuth2',
key: 'AUTH_OAUTH2'
},
{
title: this.$t('WeCom'),
name: 'WeCom',
key: 'AUTH_WECOM'
},
{
title: this.$t('DingTalk'),
name: 'DingTalk',
key: 'AUTH_DINGTALK'
},
{
title: this.$t('FeiShu'),
name: 'FeiShu',
key: 'AUTH_FEISHU'
},
{
title: 'Lark',
name: 'Lark',
key: 'AUTH_LARK'
},
{
title: this.$t('Slack'),
name: 'Slack',
key: 'AUTH_SLACK'
},
{
title: this.$t('Radius'),
name: 'Radius',
key: 'AUTH_RADIUS'
}
],
ldapHABackends: [
{
title: this.$t('LDAP HA'),
name: 'LdapHA',
key: 'AUTH_LDAP_HA'
}
],
authMethods: [],
submenu: []
}
},
computed: {
componentData() {
return {}
}
},
created() {
this.filterAuthItems()
},
mounted() {
this.$axios.get('/api/v1/settings/setting/?category=auth').then(res => {
for (const item of this.submenu) {
const key = item.key
if (!key) {
continue
}
if (res[key]) {
item.icon = 'fa-check-circle text-primary'
}
}
}).finally(() => {
this.loading = false
})
},
methods: {
updateActiveMenu(key, status) {
const targetTab =
this.extraBackends.find((item) => item.key === key) ||
this.ldapHABackends.find((item) => item.key === key) ||
this.defaultBackends.find((item) => item.key === key)
status ? this.submenu.push(targetTab) : this.submenu.splice(this.submenu.indexOf(targetTab), 1)
},
filterAuthItems() {
const authItems = authLocalStorage.get('authItems')
const defaultBackends = this.defaultBackends.filter((defaultItem) => {
const authItem = authItems.find((item) => item.enabled && item.authKey === defaultItem.key)
return authItem
})
const ldapHABackends = this.ldapHABackends.filter((ldapHABackendItem) => {
const authItem = authItems.find((item) => item.enabled && item.authKey === ldapHABackendItem.key)
return authItem
})
const extraBackends = this.extraBackends.filter((extraItem) => {
const authItem = authItems.find((item) => item.enabled && item.authKey === extraItem.key)
return authItem
})
this.submenu = [
...mapState({
authMethodsSetting: state => state.settings.authMethods
}),
menu() {
return [
{
title: this.$t('Basic'),
name: 'Basic'
},
...defaultBackends,
...ldapHABackends,
...extraBackends
...this.authMethods.map(item => {
return {
...item,
hidden: () => !this.authMethodsSetting[item.authKey]
}
})
]
}
},
created() {
this.$store.dispatch('settings/getAuthMethods').then()
},
async mounted() {
this.authMethods = await getAuthItems()
this.loading = false
}
}
</script>