@
前端程式碼的框架採用vue.js + elementUI 這套較為簡單的方式實現,以及typescript語法更方便閱讀。
首先新增全域性物件:
loginForm: 登入表單物件
twoFactorData: 兩步驗證資料,
showTwoFactorSuccess: 是否顯示兩步驗證成功提示
loginForm: {
//登入物件
username: "",
password: "",
twoFactorAuthenticationToken: "",
twoFactorAuthenticationProvider: "Phone",
},
twoFactorData: null,
showTwoFactorSuccess: false,
傳送驗證碼
編寫傳送驗證碼函式sendVerificationCode,傳送驗證碼後,啟動定時器,60秒後可以再次傳送驗證碼。
async sendVerificationCode() {
this.smsSendCd = 60;
this.timer = setInterval(() => {
this.smsSendCd--;
if (this.smsSendCd <= 0) {
clearInterval(this.timer);
}
}, 1000);
await request(
`${this.host}api/TokenAuth/SendTwoFactorAuthenticateCaptcha`,
"post",
{
provider: "Phone",
userId: this.twoFactorData.userId,
}
)
.catch((re) => {
var res = re.response.data;
this.errorMessage(res.error.message);
})
.then((re) => {
var res = re.data.result;
this.showTwoFactorSuccess = true;
this.showTwoFactorSuccess = false;
this.successMessage("傳送驗證碼成功");
});
},
request 是利用axios庫傳送帶有訪問憑證Header請求功能的封裝 ,ajaxRequest.ts請參考博文使用 Abp.Zero 搭建第三方登入模組(三):網頁端開發
這裡使用js-cookie庫獲取cookie中的訪問憑證,並新增到Header中
import { request } from "@/ajaxRequire";
import Cookies from "js-cookie";
const tokenKey = "main_token";
const setToken = (token: string) => Cookies.set(tokenKey, token);
const cleanToken = () => Cookies.remove(tokenKey);
const getToken = () => Cookies.get(tokenKey);
登入
編寫登入函式handleLogin:
async handleLogin() {
this.loading = true;
var userNameOrEmailAddress = this.loginForm.username;
var password = this.loginForm.password;
var twoFactorAuthenticationToken =
this.loginForm.twoFactorAuthenticationToken;
var twoFactorAuthenticationProvider =
this.loginForm.twoFactorAuthenticationProvider;
userNameOrEmailAddress = userNameOrEmailAddress.trim();
await request(`${this.host}api/TokenAuth/Authenticate`, "post", {
userNameOrEmailAddress,
password,
twoFactorAuthenticationToken,
twoFactorAuthenticationProvider,
})
.catch((re) => {
var res = re.response.data;
this.errorMessage(res.error.message);
})
.then(async (res) => {
var data = res.data.result;
if (data.requiresTwoFactorAuthenticate) {
this.twoFactorData = data;
} else {
setToken(data.accessToken);
setRememberClientToken(data.rememberClientToken);
await this.getCurrentUser();
}
})
.finally(() => {
setTimeout(() => {
this.loading = false;
}, 1.5 * 1000);
});
},
請注意,當需要進行兩步驗證時,requiresTwoFactorAuthenticate會返回true,同時返回
twoFactorAuthenticationProviders。
退出登入
登出, 將Token以及使用者資訊置空
<el-button
:loading="loading"
type="danger"
style="width: 100%"
@click.native.prevent="logout">
退出登入
</el-button>
logout() {
setToken(null);
this.token = null;
this.userInfo = null;
},
介面控制元件
在登入表單的HTML中,新增兩步驗證控制元件:
顯示規則為,當需要兩步驗證時(即twoFactorData不為空),顯示兩步驗證控制元件,否則顯示登入控制元件。
根據twoFactorAuthenticationProviders。我們採用了兩種方式,一種是簡訊驗證碼,一種是郵箱驗證碼,這裡我們採用了elementUI的tab元件,來實現兩種方式的切換。
<el-form
ref="loginForm"
:model="loginForm"
class="login-form"
autocomplete="on"
label-position="left"
>
<template v-if="twoFactorData == null">
...
</template>
<template v-else>
<p>您的賬號開啟了兩步驗證,請選擇一種認證方式以繼續登入</p>
<el-tabs
v-model="loginForm.twoFactorAuthenticationProvider"
tab-position="top"
>
<el-tab-pane
:lazy="true"
label="SMS簡訊驗證"
name="Phone"
:disabled="
twoFactorData.twoFactorAuthenticationProviders.indexOf(
'Email'
) == -1
"
>
<el-row>
<el-col
:span="24"
style="
{
margin-bottom: 10px;
}
"
>
<el-alert
v-if="showTwoFactorSuccess"
title="驗證碼已傳送至使用者的手機號,請查收"
type="info"
>
</el-alert>
</el-col>
<el-col :span="24">
<el-form-item
class="item"
prop="twoFactorAuthenticationToken"
>
<el-input
v-model="loginForm.twoFactorAuthenticationToken"
:placeholder="'傳送驗證碼後鍵入驗證碼'"
tabindex="2"
autocomplete="on"
@blur="capsTooltip = false"
>
<el-button
slot="append"
:disabled="smsSendCd > 0"
@click="sendVerificationCode"
>{{
smsSendCd == 0 ? "傳送驗證碼" : smsSendCd + "後重試"
}}</el-button
>
</el-input>
</el-form-item>
</el-col>
</el-row>
</el-tab-pane>
<el-tab-pane
:lazy="true"
label="郵箱驗證"
name="Email"
:disabled="
twoFactorData.twoFactorAuthenticationProviders.indexOf(
'Email'
) == -1
"
>
<el-row>
<el-col :span="24">
<el-alert
v-if="showTwoFactorSuccess"
title="驗證碼已傳送至登入使用者對應的郵箱,請查收"
type="info"
>
</el-alert>
</el-col>
<el-col :span="24">
...
</el-col>
</el-row>
</el-tab-pane>
</el-tabs>
</template>
<el-row type="flex" class="row-bg" justify="center" :gutter="10">
<el-col :span="10" v-if="twoFactorData != null">
<el-button
:loading="loading"
style="width: 100%"
@click.native.prevent="twoFactorData = null"
>
返回
</el-button>
</el-col>
<el-col :span="10">
<el-button
:loading="loading"
type="primary"
style="width: 100%"
@click.native.prevent="handleLogin"
>
{{ twoFactorData == null ? "登入" : "繼續" }}
</el-button>
</el-col>
</el-row>
</el-form>
獲取使用者資訊功能
登入成功後我們要拿到當前使用者的資訊,存入userInfo物件,並在頁面上簡單展示
<span>{{ userInfo }}</span>
建立一個獲取當前使用者的函式
async getCurrentUser() {
await request(
`${this.host}${this.prefix}/User/GetCurrentUser`,
"get",
null
)
.catch((re) => {
var res = re.response.data;
this.errorMessage(res.error.message);
})
.then(async (re) => {
var result = re.data.result as any;
this.userInfo = result;
this.token = getToken();
clearInterval(this.timer);
this.smsSendCd = 0;
this.currentVerifyingType = null;
this.successMessage("登入成功");
});
}
最終效果