mirror of
https://github.com/jumpserver/lina.git
synced 2025-09-19 17:54:37 +00:00
perf: confirm 优化
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<UserConfirmDialog
|
<UserConfirmDialog
|
||||||
|
:url="url"
|
||||||
@UserConfirmDone="getAuthInfo"
|
@UserConfirmDone="getAuthInfo"
|
||||||
@UserConfirmCancel="exit"
|
@UserConfirmCancel="exit"
|
||||||
/>
|
/>
|
||||||
@@ -57,13 +58,13 @@ export default {
|
|||||||
return {
|
return {
|
||||||
dialogTitle: this.$t('common.ViewSecret'),
|
dialogTitle: this.$t('common.ViewSecret'),
|
||||||
authInfo: {},
|
authInfo: {},
|
||||||
showAuthInfo: false
|
showAuthInfo: false,
|
||||||
|
url: `/api/v1/assets/account-secrets/${this.account.id}/`
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
getAuthInfo() {
|
getAuthInfo() {
|
||||||
const url = `/api/v1/assets/account-secrets/${this.account.id}/`
|
this.$axios.get(this.url, { disableFlashErrorMsg: true }).then(resp => {
|
||||||
this.$axios.get(url, { disableFlashErrorMsg: true }).then(resp => {
|
|
||||||
this.authInfo = resp
|
this.authInfo = resp
|
||||||
this.showAuthInfo = true
|
this.showAuthInfo = true
|
||||||
})
|
})
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<UserConfirmDialog
|
<UserConfirmDialog
|
||||||
|
:url="url"
|
||||||
@UserConfirmDone="getAuthInfo"
|
@UserConfirmDone="getAuthInfo"
|
||||||
@UserConfirmCancel="exit"
|
@UserConfirmCancel="exit"
|
||||||
/>
|
/>
|
||||||
@@ -54,13 +55,13 @@ export default {
|
|||||||
return {
|
return {
|
||||||
dialogTitle: this.$t('common.ViewSecret'),
|
dialogTitle: this.$t('common.ViewSecret'),
|
||||||
authInfo: {},
|
authInfo: {},
|
||||||
showAuthInfo: false
|
showAuthInfo: false,
|
||||||
|
url: `/api/v1/applications/account-secrets/${this.account.id}/`
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
getAuthInfo() {
|
getAuthInfo() {
|
||||||
const url = `/api/v1/applications/account-secrets/${this.account.id}/`
|
this.$axios.get(this.url, { disableFlashErrorMsg: true }).then(resp => {
|
||||||
this.$axios.get(url, { disableFlashErrorMsg: true }).then(resp => {
|
|
||||||
this.authInfo = resp
|
this.authInfo = resp
|
||||||
this.showAuthInfo = true
|
this.showAuthInfo = true
|
||||||
})
|
})
|
||||||
|
@@ -1,28 +1,88 @@
|
|||||||
<template>
|
<template>
|
||||||
<Dialog
|
<Dialog
|
||||||
:title="$t('common.CurrentUserVerify')"
|
:title="title"
|
||||||
:width="'50'"
|
:width="'36%'"
|
||||||
:show-confirm="false"
|
:show-confirm="false"
|
||||||
:show-cancel="false"
|
:show-cancel="false"
|
||||||
:visible.sync="visible"
|
:visible.sync="visible"
|
||||||
:destroy-on-close="true"
|
:destroy-on-close="true"
|
||||||
v-bind="$attrs"
|
v-bind="$attrs"
|
||||||
|
class="dialog-content"
|
||||||
v-on="$listeners"
|
v-on="$listeners"
|
||||||
>
|
>
|
||||||
<el-row :gutter="20">
|
<div v-if="ConfirmType === 'relogin'">
|
||||||
<el-col :md="4" :sm="24">
|
<el-row :gutter="24" style="margin: 0 auto;">
|
||||||
<div style="line-height: 34px;text-align: center">{{ Label }}</div>
|
<el-col :md="24" :sm="24">
|
||||||
|
<el-alert
|
||||||
|
:title="this.$t('auth.ReLoginTitle')"
|
||||||
|
type="info"
|
||||||
|
center
|
||||||
|
:closable="false"
|
||||||
|
style="margin-bottom: 20px;"
|
||||||
|
/>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :md="14" :sm="24">
|
</el-row>
|
||||||
<el-input v-model="SecretKey" :show-password="showPassword" />
|
<el-row :gutter="24" style="margin: 0 auto;">
|
||||||
<span class="help-tips help-block">{{ HelpText }}</span>
|
<el-col :md="24" :sm="24">
|
||||||
|
<el-button
|
||||||
|
size="mini"
|
||||||
|
type="primary"
|
||||||
|
style="width: 100%; line-height:20px;"
|
||||||
|
@click="logOut"
|
||||||
|
>
|
||||||
|
{{ this.$t('auth.ReLogin') }}
|
||||||
|
</el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :md="4" :sm="24">
|
</el-row>
|
||||||
<el-button size="mini" type="primary" style="line-height:20px " @click="userConfirm">
|
</div>
|
||||||
|
<div v-else>
|
||||||
|
<el-row :gutter="24" style="margin: 0 auto;">
|
||||||
|
<el-col :span="24" :md="24" :sm="24" class="add">
|
||||||
|
<el-select
|
||||||
|
v-model="Select"
|
||||||
|
:disabled="ConfirmType === 'password'"
|
||||||
|
style="width: 100%; margin-bottom: 20px;"
|
||||||
|
@change="helpText(Select)"
|
||||||
|
>
|
||||||
|
<el-option
|
||||||
|
v-for="(item, i) of Content"
|
||||||
|
:key="i"
|
||||||
|
:label="item.display_name"
|
||||||
|
:value="item.name"
|
||||||
|
:disabled="item.disabled"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
<el-row :gutter="24" style="margin: 0 auto;">
|
||||||
|
<el-col :md="24 - smsWidth" :sm="24">
|
||||||
|
<el-input v-model="SecretKey" :show-password="showPassword" :placeholder="HelpText" style="margin-bottom: 20px;" />
|
||||||
|
</el-col>
|
||||||
|
<el-col v-if="Select === 'sms'" :md="smsWidth" :sm="24">
|
||||||
|
<el-button
|
||||||
|
size="mini"
|
||||||
|
type="primary"
|
||||||
|
style="line-height:20px; float: right;"
|
||||||
|
:disabled="smsBtndisabled"
|
||||||
|
@click="sendChallengeCode"
|
||||||
|
>
|
||||||
|
{{ smsBtnText }}
|
||||||
|
</el-button>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
<el-row :gutter="24" style="margin: 0 auto;">
|
||||||
|
<el-col :md="24" :sm="24">
|
||||||
|
<el-button
|
||||||
|
size="mini"
|
||||||
|
type="primary"
|
||||||
|
style="width: 100%; line-height:20px;"
|
||||||
|
@click="userConfirm"
|
||||||
|
>
|
||||||
{{ this.$t('common.Confirm') }}
|
{{ this.$t('common.Confirm') }}
|
||||||
</el-button>
|
</el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
|
</div>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
@@ -33,11 +93,23 @@ export default {
|
|||||||
components: {
|
components: {
|
||||||
Dialog
|
Dialog
|
||||||
},
|
},
|
||||||
|
props: {
|
||||||
|
url: {
|
||||||
|
type: String,
|
||||||
|
default: () => ''
|
||||||
|
}
|
||||||
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
Label: '',
|
title: '',
|
||||||
|
smsWidth: 0,
|
||||||
|
Select: '',
|
||||||
|
Level: null,
|
||||||
HelpText: '',
|
HelpText: '',
|
||||||
|
smsBtnText: '',
|
||||||
|
smsBtndisabled: false,
|
||||||
ConfirmType: '',
|
ConfirmType: '',
|
||||||
|
Content: null,
|
||||||
SecretKey: '',
|
SecretKey: '',
|
||||||
visible: false
|
visible: false
|
||||||
}
|
}
|
||||||
@@ -59,37 +131,72 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.$axios.get('/api/v1/authentication/confirm/', { disableFlashErrorMsg: true }).then(() => {
|
this.smsBtnText = this.$t('common.SendVerificationCode')
|
||||||
this.$emit('UserConfirmDone', true)
|
this.$axios.get(`${this.url}`, { disableFlashErrorMsg: true }).then(
|
||||||
}).catch(err => {
|
() => { this.$emit('UserConfirmDone', true) }).catch((err) => {
|
||||||
this.$log.debug('Verify otp code error: ', err)
|
const confirm_type = err.response.data.code
|
||||||
const backends = err.response.data.backends
|
this.$axios.get('/api/v1/authentication/confirm/', { params: { confirm_type: confirm_type }}).then((data) => {
|
||||||
backends.sort((a, b) => b.level - a.level)
|
this.ConfirmType = data.confirm_type
|
||||||
this.ConfirmType = backends[0].name
|
this.Content = data.content
|
||||||
if (this.ConfirmType === 'relogin') {
|
if (this.ConfirmType === 'relogin') {
|
||||||
this.visible = false
|
this.title = this.$t('auth.NeedReLogin')
|
||||||
return this.$message.error(this.$t('auth.ReLoginErr'))
|
this.visible = true
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.ConfirmType === 'mfa') {
|
if (this.ConfirmType === 'mfa') {
|
||||||
this.Label = 'MFA'
|
this.Select = this.Content.filter(item => !item.disabled)[0].name
|
||||||
this.HelpText = this.$t('common.MFARequireForSecurity')
|
this.HelpText = this.Content.filter(item => !item.disabled)[0].placeholder
|
||||||
this.visible = true
|
|
||||||
} else if (this.ConfirmType === 'password') {
|
} else if (this.ConfirmType === 'password') {
|
||||||
this.Label = this.$t('setting.password')
|
this.Select = this.$t('setting.password')
|
||||||
this.HelpText = this.$t('common.PasswordRequireForSecurity')
|
this.HelpText = this.$t('common.PasswordRequireForSecurity')
|
||||||
this.visible = true
|
this.Content = [{ 'name': 'password' }]
|
||||||
}
|
}
|
||||||
|
this.title = this.$t('common.CurrentUserVerify')
|
||||||
|
this.visible = true
|
||||||
|
})
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
helpText(val) {
|
||||||
|
this.HelpText = this.Content.filter(item => item.name === val)[0]?.placeholder
|
||||||
|
if (val === 'sms') {
|
||||||
|
this.smsWidth = 6
|
||||||
|
} else {
|
||||||
|
this.smsWidth = 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
logOut() {
|
||||||
|
window.location.href = `${process.env.VUE_APP_LOGOUT_PATH}?next=${this.$route.fullPath}`
|
||||||
|
},
|
||||||
|
sendChallengeCode() {
|
||||||
|
this.$axios.post(
|
||||||
|
`/api/v1/authentication/mfa/select/`, {
|
||||||
|
type: 'sms'
|
||||||
|
}
|
||||||
|
).then(res => {
|
||||||
|
this.$message.success(this.$t('common.VerificationCodeSent'))
|
||||||
|
let time = 60
|
||||||
|
const interval = setInterval(() => {
|
||||||
|
this.smsBtnText = this.$t('common.Pending') + `: ${time}`
|
||||||
|
this.smsBtndisabled = true
|
||||||
|
time -= 1
|
||||||
|
|
||||||
|
if (time === 0) {
|
||||||
|
this.smsBtnText = this.$t('common.SendVerificationCode')
|
||||||
|
this.smsBtndisabled = false
|
||||||
|
clearInterval(interval)
|
||||||
|
}
|
||||||
|
}, 1000)
|
||||||
|
})
|
||||||
|
},
|
||||||
userConfirm() {
|
userConfirm() {
|
||||||
if (this.ConfirmType === 'mfa' && this.SecretKey.length !== 6) {
|
if (this.Select === 'otp' && this.SecretKey.length !== 6) {
|
||||||
return this.$message.error(this.$tc('common.MFAErrorMsg'))
|
return this.$message.error(this.$t('common.MFAErrorMsg'))
|
||||||
}
|
}
|
||||||
this.$axios.post(
|
this.$axios.post(
|
||||||
`/api/v1/authentication/confirm/`, {
|
`/api/v1/authentication/confirm/`, {
|
||||||
confirm_type: this.ConfirmType,
|
confirm_type: this.ConfirmType,
|
||||||
|
mfa_type: this.ConfirmType === 'password' ? undefined : this.Select,
|
||||||
secret_key: this.SecretKey
|
secret_key: this.SecretKey
|
||||||
}
|
}
|
||||||
).then(res => {
|
).then(res => {
|
||||||
@@ -100,6 +207,12 @@ export default {
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style lang="scss" scoped>
|
||||||
|
.dialog-content >>> .el-dialog__footer{
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog-content >>> .el-dialog{
|
||||||
|
padding: 8px;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@@ -247,9 +247,13 @@
|
|||||||
"auth": {
|
"auth": {
|
||||||
"LoginRequiredMsg": "You account has logout, Please login again",
|
"LoginRequiredMsg": "You account has logout, Please login again",
|
||||||
"ReLogin": "Re-Login",
|
"ReLogin": "Re-Login",
|
||||||
|
"ReLoginTitle": "The current three-party login user (cas/saml) is not bound to MFA and does not support password verification. Please login again",
|
||||||
|
"NeedReLogin": "Need Re-Login",
|
||||||
"ReLoginErr": "Login time has exceeded 5 minutes, please login again"
|
"ReLoginErr": "Login time has exceeded 5 minutes, please login again"
|
||||||
},
|
},
|
||||||
"common": {
|
"common": {
|
||||||
|
"VerificationCodeSent": "The verification code has been sent",
|
||||||
|
"SendVerificationCode": "Send verification code",
|
||||||
"ChangeViewHelpText": "Click to change view",
|
"ChangeViewHelpText": "Click to change view",
|
||||||
"Component": "component",
|
"Component": "component",
|
||||||
"PrivateCloud": "Private cloud",
|
"PrivateCloud": "Private cloud",
|
||||||
|
@@ -252,9 +252,13 @@
|
|||||||
"auth": {
|
"auth": {
|
||||||
"LoginRequiredMsg": "アカウントが終了しました。ログインし直してください",
|
"LoginRequiredMsg": "アカウントが終了しました。ログインし直してください",
|
||||||
"ReLogin": "再ログイン",
|
"ReLogin": "再ログイン",
|
||||||
|
"ReLoginTitle": "現在、サードパーティのログインユーザー(CAS/SAML)は、MFAをバインドしておらず、パスワードチェックをサポートしていません。再ログインしてください。",
|
||||||
|
"NeedReLogin": "再ログインが必要です",
|
||||||
"ReLoginErr": "ログイン時間が 5 分を超えました。もう一度ログインしてください"
|
"ReLoginErr": "ログイン時間が 5 分を超えました。もう一度ログインしてください"
|
||||||
},
|
},
|
||||||
"common": {
|
"common": {
|
||||||
|
"VerificationCodeSent": "検証コードが送信されました",
|
||||||
|
"SendVerificationCode": "認証コードの送信",
|
||||||
"ChangeViewHelpText": "クリックしてさまざまなビューにアクセス",
|
"ChangeViewHelpText": "クリックしてさまざまなビューにアクセス",
|
||||||
"Component": "コンポーネント",
|
"Component": "コンポーネント",
|
||||||
"PrivateCloud": "プライベートクラウド",
|
"PrivateCloud": "プライベートクラウド",
|
||||||
|
@@ -252,9 +252,13 @@
|
|||||||
"auth": {
|
"auth": {
|
||||||
"LoginRequiredMsg": "账号已退出,请重新登录",
|
"LoginRequiredMsg": "账号已退出,请重新登录",
|
||||||
"ReLogin": "重新登录",
|
"ReLogin": "重新登录",
|
||||||
|
"ReLoginTitle": "当前三方登录用户(CAS/SAML),未绑定 MFA 且不支持密码校验,请重新登录。",
|
||||||
|
"NeedReLogin": "需要重新登录",
|
||||||
"ReLoginErr": "登录时长已超过 5 分钟,请重新登录"
|
"ReLoginErr": "登录时长已超过 5 分钟,请重新登录"
|
||||||
},
|
},
|
||||||
"common": {
|
"common": {
|
||||||
|
"VerificationCodeSent": "验证码已发送",
|
||||||
|
"SendVerificationCode": "发送验证码",
|
||||||
"ChangeViewHelpText": "点击切换不同视图",
|
"ChangeViewHelpText": "点击切换不同视图",
|
||||||
"Component": "组件",
|
"Component": "组件",
|
||||||
"PrivateCloud": "私有云",
|
"PrivateCloud": "私有云",
|
||||||
|
@@ -2,6 +2,7 @@
|
|||||||
<Page v-bind="$attrs">
|
<Page v-bind="$attrs">
|
||||||
<UserConfirmDialog
|
<UserConfirmDialog
|
||||||
v-if="showPasswordDialog"
|
v-if="showPasswordDialog"
|
||||||
|
:url="confirmUrl"
|
||||||
:visible.sync="showPasswordDialog"
|
:visible.sync="showPasswordDialog"
|
||||||
@UserConfirmDone="verifyDone"
|
@UserConfirmDone="verifyDone"
|
||||||
@UserConfirmCancel="exit"
|
@UserConfirmCancel="exit"
|
||||||
@@ -284,6 +285,15 @@ export default {
|
|||||||
key: this.$t('users.Comment')
|
key: this.$t('users.Comment')
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
confirmUrl() {
|
||||||
|
let url = ''
|
||||||
|
if (!this.object[`is_${this.currentEdit}_bound`]) {
|
||||||
|
url = `/core/auth/${this.currentEdit}/qr/bind/?redirect_url=${this.$route.fullPath}`
|
||||||
|
} else {
|
||||||
|
url = `/api/v1/authentication/${this.currentEdit}/qr/unbind/`
|
||||||
|
}
|
||||||
|
return url
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
@@ -309,10 +319,11 @@ export default {
|
|||||||
return backendList
|
return backendList
|
||||||
},
|
},
|
||||||
verifyDone() {
|
verifyDone() {
|
||||||
|
const url = this.confirmUrl
|
||||||
if (!this.object[`is_${this.currentEdit}_bound`]) {
|
if (!this.object[`is_${this.currentEdit}_bound`]) {
|
||||||
window.location.href = `/core/auth/${this.currentEdit}/qr/bind/?redirect_url=${this.$route.fullPath}`
|
window.location.href = url
|
||||||
} else {
|
} else {
|
||||||
this.$axios.post(`/api/v1/authentication/${this.currentEdit}/qr/unbind/`).then(res => {
|
this.$axios.post(url).then(res => {
|
||||||
this.$message.success(this.$t('common.updateSuccessMsg'))
|
this.$message.success(this.$t('common.updateSuccessMsg'))
|
||||||
this.$store.dispatch('users/getProfile')
|
this.$store.dispatch('users/getProfile')
|
||||||
})
|
})
|
||||||
|
Reference in New Issue
Block a user