mirror of
https://github.com/jumpserver/lina.git
synced 2026-01-15 14:24:39 +00:00
perf: update auth intergration
This commit is contained in:
@@ -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)
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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%;
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user