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