浏览代码

add 2step chatcha

Sendya 6 年之前
父节点
当前提交
e60479ebd5
共有 2 个文件被更改,包括 190 次插入80 次删除
  1. 79 0
      src/components/tools/TwoStepCaptcha.vue
  2. 111 80
      src/views/Login.vue

+ 79 - 0
src/components/tools/TwoStepCaptcha.vue

@@ -0,0 +1,79 @@
+<template>
+  <!-- 两步验证 -->
+  <a-modal
+    centered
+    v-model="visible"
+    @cancel="handleCancel"
+    :maskClosable="false"
+  >
+    <div slot="title" :style="{ textAlign: 'center' }">两步验证</div>
+    <template slot="footer">
+      <div :style="{ textAlign: 'center' }">
+        <a-button key="back" @click="visible = false">返回</a-button>
+        <a-button key="submit" type="primary" :loading="stepLoading" @click="handleStepOk">
+          继续
+        </a-button>
+      </div>
+    </template>
+
+    <a-spin :spinning="stepLoading">
+      <a-form layout="vertical" :auto-form-create="(form)=>{this.form = form}">
+        <p style="text-align: center" v-if="!stepLoading">请在手机中打开 Google Authenticator 或两步验证 APP<br />输入 6 位动态码</p>
+        <p style="text-align: center" v-else>正在验证..<br/>请稍后</p>
+        <a-form-item
+          :style="{ textAlign: 'center' }"
+          hasFeedback
+          fieldDecoratorId="stepCode"
+          :fieldDecoratorOptions="{rules: [{ required: true, message: '请输入 6 位动态码!', pattern: /^\d{6}$/, len: 6 }]}"
+        >
+          <a-input :style="{ textAlign: 'center' }" placeholder="000000" />
+        </a-form-item>
+        <p style="text-align: center">
+          <a @click="onForgeStepCode">遗失手机?</a>
+        </p>
+      </a-form>
+    </a-spin>
+  </a-modal>
+</template>
+
+<script>
+export default {
+  props: {
+    visible: {
+      type: Boolean,
+      default: false
+    }
+  },
+  data() {
+    return {
+      stepLoading: false,
+
+      form: null
+    };
+  },
+  methods: {
+    handleStepOk() {
+      const vm = this
+      this.stepLoading = true
+      this.form.validateFields((err, values) => {
+        if (!err) {
+          console.log('values', values)
+          setTimeout( () => {
+            vm.stepLoading = false
+            vm.$emit('success', { values })
+          }, 2000)
+          return;
+        }
+        this.stepLoading = false
+        this.$emit('error', { err })
+      })
+    },
+    handleCancel () {
+
+    },
+    onForgeStepCode() {
+      
+    }
+  }
+};
+</script>

+ 111 - 80
src/views/Login.vue

@@ -1,103 +1,112 @@
 <template>
-  <a-form class="user-layout-login" ref="formLogin" :autoFormCreate="(form)=>{this.form = form}" id="formLogin">
-    <a-tabs
-      :activeKey="customActiveKey"
-      :tabBarStyle="{ textAlign: 'center', borderBottom: 'unset' }"
-      @change="handleTabClick">
-      <a-tab-pane key="tab1" tab="账号密码登陆">
+  <div>
+    <a-form class="user-layout-login" ref="formLogin" :autoFormCreate="(form)=>{this.form = form}" id="formLogin">
+      <a-tabs
+        :activeKey="customActiveKey"
+        :tabBarStyle="{ textAlign: 'center', borderBottom: 'unset' }"
+        @change="handleTabClick">
+        <a-tab-pane key="tab1" tab="账号密码登陆">
 
-        <a-form-item
-          fieldDecoratorId="username"
-          :fieldDecoratorOptions="{rules: [{ required: true, message: '请输入帐户名或邮箱地址' }, { validator: this.handleUsernameOrEmail }], validateTrigger: 'blur'}"
-        >
-          <a-input size="large" type="text" v-model="formLogin.username" placeholder="帐户名或邮箱地址 / admin">
-            <a-icon slot="prefix" type='user' :style="{ color: 'rgba(0,0,0,.25)' }"/>
-          </a-input>
-        </a-form-item>
+          <a-form-item
+            fieldDecoratorId="username"
+            :fieldDecoratorOptions="{rules: [{ required: true, message: '请输入帐户名或邮箱地址' }, { validator: this.handleUsernameOrEmail }], validateTrigger: 'blur'}"
+          >
+            <a-input size="large" type="text" v-model="formLogin.username" placeholder="帐户名或邮箱地址 / admin">
+              <a-icon slot="prefix" type='user' :style="{ color: 'rgba(0,0,0,.25)' }"/>
+            </a-input>
+          </a-form-item>
 
-        <a-form-item
-          fieldDecoratorId="password"
-          :fieldDecoratorOptions="{rules: [{ required: true, message: '请输入密码' }], validateTrigger: 'blur'}">
-          <a-input size="large" type="password" v-model="formLogin.password" placeholder="密码 / admin">
-            <a-icon slot="prefix" type='lock' :style="{ color: 'rgba(0,0,0,.25)' }"/>
-          </a-input>
-        </a-form-item>
-      </a-tab-pane>
-      <a-tab-pane key="tab2" tab="手机号登陆">
-        <a-form-item
-          fieldDecoratorId="mobile"
-          :fieldDecoratorOptions="{rules: [{ required: true, pattern: /^1[34578]\d{9}$/, message: '请输入正确的手机号' }], validateTrigger: 'blur'}">
-          <a-input size="large" type="text" v-model="formLogin.mobile" placeholder="手机号">
-            <a-icon slot="prefix" type='mobile' :style="{ color: 'rgba(0,0,0,.25)' }"/>
-          </a-input>
-        </a-form-item>
+          <a-form-item
+            fieldDecoratorId="password"
+            :fieldDecoratorOptions="{rules: [{ required: true, message: '请输入密码' }], validateTrigger: 'blur'}">
+            <a-input size="large" type="password" v-model="formLogin.password" placeholder="密码 / admin">
+              <a-icon slot="prefix" type='lock' :style="{ color: 'rgba(0,0,0,.25)' }"/>
+            </a-input>
+          </a-form-item>
+        </a-tab-pane>
+        <a-tab-pane key="tab2" tab="手机号登陆">
+          <a-form-item
+            fieldDecoratorId="mobile"
+            :fieldDecoratorOptions="{rules: [{ required: true, pattern: /^1[34578]\d{9}$/, message: '请输入正确的手机号' }], validateTrigger: 'blur'}">
+            <a-input size="large" type="text" v-model="formLogin.mobile" placeholder="手机号">
+              <a-icon slot="prefix" type='mobile' :style="{ color: 'rgba(0,0,0,.25)' }"/>
+            </a-input>
+          </a-form-item>
 
-        <a-row :gutter="16">
-          <a-col class="gutter-row" :span="16">
-            <a-form-item
-              fieldDecoratorId="captcha"
-              :fieldDecoratorOptions="{rules: [{ required: true, message: '请输入验证码' }], validateTrigger: 'blur'}">
-              <a-input size="large" type="text" v-model="formLogin.captcha" placeholder="验证码">
-                <a-icon slot="prefix" type='mail' :style="{ color: 'rgba(0,0,0,.25)' }"/>
-              </a-input>
-            </a-form-item>
-          </a-col>
-          <a-col class="gutter-row" :span="8">
-            <a-button
-              class="getCaptcha"
-              :disabled="state.smsSendBtn"
-              @click.stop.prevent="getCaptcha"
-              v-text="!state.smsSendBtn&&'获取验证码'||(state.time+' s')"></a-button>
-          </a-col>
-        </a-row>
-      </a-tab-pane>
-    </a-tabs>
+          <a-row :gutter="16">
+            <a-col class="gutter-row" :span="16">
+              <a-form-item
+                fieldDecoratorId="captcha"
+                :fieldDecoratorOptions="{rules: [{ required: true, message: '请输入验证码' }], validateTrigger: 'blur'}">
+                <a-input size="large" type="text" v-model="formLogin.captcha" placeholder="验证码">
+                  <a-icon slot="prefix" type='mail' :style="{ color: 'rgba(0,0,0,.25)' }"/>
+                </a-input>
+              </a-form-item>
+            </a-col>
+            <a-col class="gutter-row" :span="8">
+              <a-button
+                class="getCaptcha"
+                :disabled="state.smsSendBtn"
+                @click.stop.prevent="getCaptcha"
+                v-text="!state.smsSendBtn&&'获取验证码'||(state.time+' s')"></a-button>
+            </a-col>
+          </a-row>
+        </a-tab-pane>
+      </a-tabs>
 
-    <a-form-item>
-      <a-checkbox v-model="formLogin.rememberMe">自动登陆</a-checkbox>
-      <router-link :to="{ name: 'recover', params: { user: 'aaa'} }" class="forge-password" style="float: right;">
-        忘记密码
-      </router-link>
-    </a-form-item>
+      <a-form-item>
+        <a-checkbox v-model="formLogin.rememberMe">自动登陆</a-checkbox>
+        <router-link :to="{ name: 'recover', params: { user: 'aaa'} }" class="forge-password" style="float: right;">
+          忘记密码
+        </router-link>
+      </a-form-item>
 
-    <a-form-item style="margin-top:24px">
-      <a-button
-        size="large"
-        type="primary"
-        htmlType="submit"
-        class="login-button"
-        :loading="loginBtn"
-        @click.stop.prevent="handleSubmit"
-        :disabled="loginBtn">确定
-      </a-button>
-    </a-form-item>
+      <a-form-item style="margin-top:24px">
+        <a-button
+          size="large"
+          type="primary"
+          htmlType="submit"
+          class="login-button"
+          :loading="loginBtn"
+          @click.stop.prevent="handleSubmit"
+          :disabled="loginBtn">确定
+        </a-button>
+      </a-form-item>
 
-    <div class="user-login-other">
-      <span>其他登陆方式</span>
-      <a><a-icon class="item-icon" type="alipay-circle"></a-icon></a>
-      <a><a-icon class="item-icon" type="taobao-circle"></a-icon></a>
-      <a><a-icon class="item-icon" type="weibo-circle"></a-icon></a>
-      <router-link class="register" :to="{ name: 'register' }">
-        注册账户
-      </router-link>
-    </div>
+      <div class="user-login-other">
+        <span>其他登陆方式</span>
+        <a><a-icon class="item-icon" type="alipay-circle"></a-icon></a>
+        <a><a-icon class="item-icon" type="taobao-circle"></a-icon></a>
+        <a><a-icon class="item-icon" type="weibo-circle"></a-icon></a>
+        <router-link class="register" :to="{ name: 'register' }">
+          注册账户
+        </router-link>
+      </div>
+    </a-form>
 
-  </a-form>
+    <two-step-captcha v-if="requiredTwoStepCaptcha" :visible="stepCaptchaVisible" @success="stepCaptchaSuccess"></two-step-captcha>
+  </div>
 </template>
 
 <script>
   import md5 from "md5"
   import api from '@/api/'
+  import TwoStepCaptcha from '@/components/tools/TwoStepCaptcha'
   import { mapActions } from "vuex"
   import { timeFix } from "@/utils/util"
 
   export default {
+    components: {
+      TwoStepCaptcha
+    },
     data () {
       return {
         customActiveKey: "tab1",
         loginBtn: false,
         // login type: 0 email, 1 username, 2 telephone
         loginType: 0,
+        requiredTwoStepCaptcha: true,
+        stepCaptchaVisible: false,
         form: null,
         state: {
           time: 60,
@@ -112,6 +121,18 @@
         },
       }
     },
+    created () {
+      /* 
+      this.$http.get('/auth/2step-code')
+        .then(res => {
+          this.requiredTwoStepCaptcha = res.result
+        }).catch(err => {
+          console.log('2step-code:', err)
+        })
+      */
+     this.requiredTwoStepCaptcha = true
+      
+    },
     methods: {
       ...mapActions([ "Login" ]),
       // handler
@@ -171,9 +192,11 @@
         }
 
         that.Login(loginParams).then(() => {
-          that.loginBtn = false
-          that.$router.push({ name: "dashboard" })
-          that.$message.success(timeFix() + ',欢迎回来', 3)
+          if (that.requiredTwoStepCaptcha) {
+            that.stepCaptchaVisible = true
+          } else {
+            that.loginSuccess()
+          }
         }).catch((err) => {
           that.requestFailed(err);
         })
@@ -217,6 +240,14 @@
           }
         );
       },
+      stepCaptchaSuccess () {
+        this.loginSuccess()
+      },
+      loginSuccess () {
+        this.loginBtn = false
+        this.$router.push({ name: "dashboard" })
+        this.$message.success(timeFix() + ',欢迎回来', 3)
+      },
       requestFailed (err) {
         this.$notification[ 'error' ]({
           message: '错误',