首页 > 其他分享 >用Abp实现两步验证(Two-Factor Authentication,2FA)登录(二):Vue网页端开发

用Abp实现两步验证(Two-Factor Authentication,2FA)登录(二):Vue网页端开发

时间:2023-04-12 14:00:11浏览次数:49  
标签:Vue 登录 res Two 验证码 Abp re var data

@

目录
前端代码的框架采用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("登录成功");
    });
}

最终效果

在这里插入图片描述

项目地址

Github:matoapp-samples

标签:Vue,登录,res,Two,验证码,Abp,re,var,data
From: https://www.cnblogs.com/jevonsflash/p/17309579.html

相关文章

  • Vue3+element-plus封装文字超出一行,省略号显示,鼠标悬浮展示全部
    1.组件封装<template><el-tooltipeffect="dark":disabled="isShowTooltip":content="content"placement="top"><p:class="['line1',className]"@mouseover="onMouseOver(refNa......
  • Vue.js 路由的props配置
    视频index.js(解构赋值,连续解构赋值)Message.vue7.路由的props配置​ 作用:让路由组件更方便的收到参数{ name:'xiangqing', path:'detail/:id', component:Detail, //第一种写法:props值为对象,该对象中所有的key-value的组合最终都会通过props传给Detail组件 //pr......
  • vue属性之监听属性(watch)
    目录简介语法示例简介当一个变量的值发生变化时,执行对应的函数语法#在属性中添加watch属性,并以需要监听变量的名字进行定义函数data:{show:'abc'}watch:{show(){我是函数内容}}示例<!DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-8">......
  • vue项目通过外部配置文件读取接口地址- 在webpack-index.html模板中使用环境变量
    概述:在index.html模板中判断当前环境,处于开发环境下时读取process环境变量、处于生产环境下时读取根目录配置文件(./config.js),两种环境下将配置统一挂载到window全局变量上(SET_CONFIG)config.jswindow.SITE_CONFIG={appTitle:'系统测试',version:'1.0.0',apiURL:''......
  • vue之组件
    目录简介全局组件语法示例局部组件语法示例组件间通信父子页面通信之父传子语法示例组件通信之子传父语法示例使用ref进行父子组件通信方法示例动态组件(component)普通方法实现使用组件component实现动态组件相关keep-alive组件之插槽(slot)匿名插槽具名插槽简介组件(component......
  • 1.Vue的基本原理
    当一个Vue实例创建时,Vue会遍历data中的属性,用Object.defineProperty(vue3.0使用proxy)将它们转为getter/setter,并且在内部追踪相关依赖,在属性被访问和修改时通知变化。每个组件实例都有相应的watcher程序实例,它会在组件渲染的过程中把属性记录为依赖,之后当依赖项的setter被调用时,会......
  • Vue3快速上手
    Vue3快速上手1.Vue3简介2020年9月18日,Vue.js发布3.0版本,代号:OnePiece(海贼王)耗时2年多、2600+次提交、30+个RFC、600+次PR、99位贡献者github上的tags地址:https://github.com/vuejs/vue-next/releases/tag/v3.0.02.Vue3带来了什么1.性能的提升打包大小减少41%初次......
  • 1.Vue的基本原理
    当一个Vue实例创建时,Vue会遍历data中的属性,用Object.defineProperty(vue3.0使用proxy)将它们转为getter/setter,并且在内部追踪相关依赖,在属性被访问和修改时通知变化。每个组件实例都有相应的watcher程序实例,它会在组件渲染的过程中把属性记录为依赖,之后当依赖项的setter被调用......
  • (一)初始vue
    data属性data属性是传入一个函数,并且该函数需要返回一个对象:在Vue2的时候,也可以传入一个对象在Vue3的时候,必须传入一个函数,否则报错data中返回的对象会被vue的响应式系统劫持,之后对该对象的修改或者访问都会在劫持中被处理:所有我们在template或者app通过{{counter}},访问......
  • #yyds干货盘点 springboot和vue搭建前后端项目实现员工的增删改查
    前言我是歌谣今天继续带来前后端项目的开发上次已经开发了部门管理,今天继续开发员工管理后端第一步empcontroller代码packagecom.itheima.controller;importcom.itheima.pojo.Emp;importcom.itheima.pojo.PageBean;importcom.itheima.pojo.Result;importcom.itheima.s......