mirror of
https://github.com/mayswind/ezbookkeeping.git
synced 2026-05-22 02:34:26 +08:00
support use 2fa backup code
This commit is contained in:
@@ -190,5 +190,11 @@ func (a *AuthorizationsApi) TwoFactorAuthorizeByRecoveryCodeHandler(c *core.Cont
|
|||||||
c.SetTokenClaims(claims)
|
c.SetTokenClaims(claims)
|
||||||
|
|
||||||
log.InfofWithRequestId(c, "[authorizations.TwoFactorAuthorizeByRecoveryCodeHandler] user \"uid:%d\" has authorized two factor via recovery code \"%s\", token will be expired at %d", user.Uid, credential.RecoveryCode, claims.ExpiresAt)
|
log.InfofWithRequestId(c, "[authorizations.TwoFactorAuthorizeByRecoveryCodeHandler] user \"uid:%d\" has authorized two factor via recovery code \"%s\", token will be expired at %d", user.Uid, credential.RecoveryCode, claims.ExpiresAt)
|
||||||
return token, nil
|
|
||||||
|
authResp := &models.AuthResponse{
|
||||||
|
Token : token,
|
||||||
|
Need2FA: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
return authResp, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,8 +4,8 @@ import "net/http"
|
|||||||
|
|
||||||
var (
|
var (
|
||||||
ErrPasscodeInvalid = NewNormalError(NORMAL_SUBCATEGORY_TWOFACTOR, 0, http.StatusUnauthorized, "passcode is invalid")
|
ErrPasscodeInvalid = NewNormalError(NORMAL_SUBCATEGORY_TWOFACTOR, 0, http.StatusUnauthorized, "passcode is invalid")
|
||||||
ErrTwoFactorRecoveryCodeInvalid = NewNormalError(NORMAL_SUBCATEGORY_TWOFACTOR, 1, http.StatusUnauthorized, "two factor recovery code is invalid")
|
ErrTwoFactorRecoveryCodeInvalid = NewNormalError(NORMAL_SUBCATEGORY_TWOFACTOR, 1, http.StatusUnauthorized, "two factor backup code is invalid")
|
||||||
ErrTwoFactorIsNotEnabled = NewNormalError(NORMAL_SUBCATEGORY_TWOFACTOR, 2, http.StatusBadRequest, "two factor is not enabled")
|
ErrTwoFactorIsNotEnabled = NewNormalError(NORMAL_SUBCATEGORY_TWOFACTOR, 2, http.StatusBadRequest, "two factor is not enabled")
|
||||||
ErrTwoFactorAlreadyEnabled = NewNormalError(NORMAL_SUBCATEGORY_TWOFACTOR, 3, http.StatusBadRequest, "two factor has already been enabled")
|
ErrTwoFactorAlreadyEnabled = NewNormalError(NORMAL_SUBCATEGORY_TWOFACTOR, 3, http.StatusBadRequest, "two factor has already been enabled")
|
||||||
ErrTwoFactorRecoveryCodeNotExist = NewNormalError(NORMAL_SUBCATEGORY_TWOFACTOR, 4, http.StatusUnauthorized, "two factor recovery code does not exist")
|
ErrTwoFactorRecoveryCodeNotExist = NewNormalError(NORMAL_SUBCATEGORY_TWOFACTOR, 4, http.StatusUnauthorized, "two factor backup code does not exist")
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -49,6 +49,15 @@ export default {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
authorize2FAByBackupCode: ({ recoveryCode, token }) => {
|
||||||
|
return axios.post('2fa/recovery.json', {
|
||||||
|
recoveryCode
|
||||||
|
}, {
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${token}`
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
logout: () => {
|
logout: () => {
|
||||||
return axios.get('v1/logout.json');
|
return axios.get('v1/logout.json');
|
||||||
},
|
},
|
||||||
|
|||||||
+6
-2
@@ -5,6 +5,7 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
'error': {
|
'error': {
|
||||||
|
'system error': 'System Error',
|
||||||
'unauthorized access': 'Unauthorized access',
|
'unauthorized access': 'Unauthorized access',
|
||||||
'token is expired': 'Token is expired',
|
'token is expired': 'Token is expired',
|
||||||
'token is invalid': 'Token is invalid',
|
'token is invalid': 'Token is invalid',
|
||||||
@@ -26,10 +27,10 @@ export default {
|
|||||||
'login name or password is invalid': 'Login name or password is invalid',
|
'login name or password is invalid': 'Login name or password is invalid',
|
||||||
'login name or password is wrong': 'Login name or password is wrong',
|
'login name or password is wrong': 'Login name or password is wrong',
|
||||||
'passcode is invalid': 'Passcode is invalid',
|
'passcode is invalid': 'Passcode is invalid',
|
||||||
'two factor recovery code is invalid': 'Two factor recovery code is invalid',
|
'two factor backup code is invalid': 'Two factor backup code is invalid',
|
||||||
'two factor is not enabled': 'Two factor is not enabled',
|
'two factor is not enabled': 'Two factor is not enabled',
|
||||||
'two factor has already been enabled': 'Two factor has already been enabled',
|
'two factor has already been enabled': 'Two factor has already been enabled',
|
||||||
'two factor recovery code does not exist': 'Two factor recovery code does not exist',
|
'two factor backup code does not exist': 'Two factor backup code does not exist',
|
||||||
},
|
},
|
||||||
'OK': 'OK',
|
'OK': 'OK',
|
||||||
'Cancel': 'Cancel',
|
'Cancel': 'Cancel',
|
||||||
@@ -53,10 +54,13 @@ export default {
|
|||||||
'Unable to login': 'Unable to login',
|
'Unable to login': 'Unable to login',
|
||||||
'Two-Factor Authentication': 'Two-Factor Authentication',
|
'Two-Factor Authentication': 'Two-Factor Authentication',
|
||||||
'Passcode': 'Passcode',
|
'Passcode': 'Passcode',
|
||||||
|
'Backup Code': 'Backup Code',
|
||||||
'Verify': 'Verify',
|
'Verify': 'Verify',
|
||||||
'Please input passcode': 'Please input passcode',
|
'Please input passcode': 'Please input passcode',
|
||||||
|
'Please input backup code': 'Please input backup code',
|
||||||
'Unable to verify': 'Unable to verify',
|
'Unable to verify': 'Unable to verify',
|
||||||
'Use a backup code': 'Use a backup code',
|
'Use a backup code': 'Use a backup code',
|
||||||
|
'Use a passcode': 'Use a passcode',
|
||||||
'Language': 'Language',
|
'Language': 'Language',
|
||||||
'Log Out': 'Log Out',
|
'Log Out': 'Log Out',
|
||||||
'Are you sure you want to log out?': 'Are you sure you want to log out?',
|
'Are you sure you want to log out?': 'Are you sure you want to log out?',
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
'error': {
|
'error': {
|
||||||
|
'system error': '系统错误',
|
||||||
'unauthorized access': '未授权的登录',
|
'unauthorized access': '未授权的登录',
|
||||||
'token is expired': '认证令牌已过期',
|
'token is expired': '认证令牌已过期',
|
||||||
'token is invalid': '认证令牌无效',
|
'token is invalid': '认证令牌无效',
|
||||||
@@ -26,10 +27,10 @@ export default {
|
|||||||
'login name or password is invalid': '登录名或密码无效',
|
'login name or password is invalid': '登录名或密码无效',
|
||||||
'login name or password is wrong': '登录名或密码错误',
|
'login name or password is wrong': '登录名或密码错误',
|
||||||
'passcode is invalid': '验证码无效',
|
'passcode is invalid': '验证码无效',
|
||||||
'two factor recovery code is invalid': '两步验证恢复口令无效',
|
'two factor backup code is invalid': '两步验证备用码无效',
|
||||||
'two factor is not enabled': '两步验证没有启用',
|
'two factor is not enabled': '两步验证没有启用',
|
||||||
'two factor has already been enabled': '两步验证已经启用',
|
'two factor has already been enabled': '两步验证已经启用',
|
||||||
'two factor recovery code does not exist': '两步验证恢复口令不存在',
|
'two factor backup code does not exist': '两步验证备用码不存在',
|
||||||
},
|
},
|
||||||
'OK': '确定',
|
'OK': '确定',
|
||||||
'Cancel': '取消',
|
'Cancel': '取消',
|
||||||
@@ -53,10 +54,13 @@ export default {
|
|||||||
'Unable to login': '无法登录',
|
'Unable to login': '无法登录',
|
||||||
'Two-Factor Authentication': '两步验证',
|
'Two-Factor Authentication': '两步验证',
|
||||||
'Passcode': '验证码',
|
'Passcode': '验证码',
|
||||||
|
'Backup Code': '备用码',
|
||||||
'Verify': '验证',
|
'Verify': '验证',
|
||||||
'Please input passcode': '请输入验证码',
|
'Please input passcode': '请输入验证码',
|
||||||
|
'Please input backup code': '请输入备用码',
|
||||||
'Unable to verify': '无法验证',
|
'Unable to verify': '无法验证',
|
||||||
'Use a backup code': '使用备用码',
|
'Use a backup code': '使用备用码',
|
||||||
|
'Use a passcode': '使用验证码',
|
||||||
'Language': '语言',
|
'Language': '语言',
|
||||||
'Log Out': '退出登录',
|
'Log Out': '退出登录',
|
||||||
'Are you sure you want to log out?': '您确定是否要退出登录?',
|
'Are you sure you want to log out?': '您确定是否要退出登录?',
|
||||||
|
|||||||
@@ -57,14 +57,23 @@
|
|||||||
type="number"
|
type="number"
|
||||||
outline
|
outline
|
||||||
clear-button
|
clear-button
|
||||||
|
v-if="twoFAVerifyType === 'passcode'"
|
||||||
:placeholder="$t('Passcode')"
|
:placeholder="$t('Passcode')"
|
||||||
:value="passcode"
|
:value="passcode"
|
||||||
@input="passcode = $event.target.value"
|
@input="passcode = $event.target.value"
|
||||||
></f7-list-input>
|
></f7-list-input>
|
||||||
|
<f7-list-input
|
||||||
|
outline
|
||||||
|
clear-button
|
||||||
|
v-if="twoFAVerifyType === 'backupcode'"
|
||||||
|
:placeholder="$t('Backup Code')"
|
||||||
|
:value="backupCode"
|
||||||
|
@input="backupCode = $event.target.value"
|
||||||
|
></f7-list-input>
|
||||||
</f7-list>
|
</f7-list>
|
||||||
<f7-button large fill :class="{ 'disabled': twoFAInputIsEmpty }" @click="verify">{{ $t('Verify') }}</f7-button>
|
<f7-button large fill :class="{ 'disabled': twoFAInputIsEmpty }" @click="verify">{{ $t('Verify') }}</f7-button>
|
||||||
<div class="margin-top text-align-center">
|
<div class="margin-top text-align-center">
|
||||||
<f7-link href="/2fa-backup-code">{{ $t('Use a backup code') }}</f7-link>
|
<f7-link @click="switch2FAVerifyType">{{ $t(twoFAVerifyTypeSwitchName) }}</f7-link>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -81,7 +90,10 @@ export default {
|
|||||||
username: '',
|
username: '',
|
||||||
password: '',
|
password: '',
|
||||||
passcode: '',
|
passcode: '',
|
||||||
|
backupCode: '',
|
||||||
tempToken: '',
|
tempToken: '',
|
||||||
|
twoFAVerifyType: 'passcode',
|
||||||
|
twoFAVerifyTypeSwitchName: 'Use a backup code',
|
||||||
allLanguages: self.$getAllLanguages()
|
allLanguages: self.$getAllLanguages()
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
@@ -90,7 +102,11 @@ export default {
|
|||||||
return !this.username || !this.password;
|
return !this.username || !this.password;
|
||||||
},
|
},
|
||||||
twoFAInputIsEmpty() {
|
twoFAInputIsEmpty() {
|
||||||
|
if (this.twoFAVerifyType === 'backupcode') {
|
||||||
|
return !this.backupCode;
|
||||||
|
} else {
|
||||||
return !this.passcode;
|
return !this.passcode;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
currentLanguageName() {
|
currentLanguageName() {
|
||||||
const currentLocale = this.$i18n.locale;
|
const currentLocale = this.$i18n.locale;
|
||||||
@@ -173,17 +189,31 @@ export default {
|
|||||||
const app = self.$f7;
|
const app = self.$f7;
|
||||||
const router = self.$f7router;
|
const router = self.$f7router;
|
||||||
|
|
||||||
if (!this.passcode) {
|
if (this.twoFAVerifyType === 'passcode' && !this.passcode) {
|
||||||
self.$alert('Please input passcode');
|
self.$alert('Please input passcode');
|
||||||
return;
|
return;
|
||||||
|
} else if (this.twoFAVerifyType === 'backupcode' && !this.backupCode) {
|
||||||
|
self.$alert('Please input backup code');
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
app.preloader.show();
|
app.preloader.show();
|
||||||
|
|
||||||
self.$services.authorize2FA({
|
let promise = null;
|
||||||
|
|
||||||
|
if (self.twoFAVerifyType === 'backupcode') {
|
||||||
|
promise = self.$services.authorize2FAByBackupCode({
|
||||||
|
recoveryCode: self.backupCode,
|
||||||
|
token: self.tempToken
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
promise = self.$services.authorize2FA({
|
||||||
passcode: self.passcode,
|
passcode: self.passcode,
|
||||||
token: self.tempToken
|
token: self.tempToken
|
||||||
}).then(response => {
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
promise.then(response => {
|
||||||
app.preloader.hide();
|
app.preloader.hide();
|
||||||
const data = response.data;
|
const data = response.data;
|
||||||
|
|
||||||
@@ -205,6 +235,15 @@ export default {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
switch2FAVerifyType() {
|
||||||
|
if (this.twoFAVerifyType === 'passcode') {
|
||||||
|
this.twoFAVerifyType = 'backupcode';
|
||||||
|
this.twoFAVerifyTypeSwitchName = 'Use a passcode';
|
||||||
|
} else {
|
||||||
|
this.twoFAVerifyType = 'passcode';
|
||||||
|
this.twoFAVerifyTypeSwitchName = 'Use a backup code';
|
||||||
|
}
|
||||||
|
},
|
||||||
changeLanguage(locale) {
|
changeLanguage(locale) {
|
||||||
this.$setLanguage(locale);
|
this.$setLanguage(locale);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user