asp. net core cooperates with vue to realize back end verification code logic

  • 2021-12-04 09:53:02
  • OfStack

Catalog Overview Partial principle Source code

Overview

The front-end verification code logic on the Internet always feels unsafe, so it is recommended to use the back-end to cooperate with verification.

If the product can be connected to the Internet, it can be verified by Tencent, Baidu and other third parties, which is convenient for docking. However, if the product may be deployed on the intranet, it must be written by itself.

This article is based on this one point.

The front-end verification code displays a picture, and the back-end generates a picture.

Partial principle

1. When the front end calls the raw end to obtain the picture, an roomID is passed in, and the back end generates a 4-bit test code and puts it into redis. Then generate a picture to return.
2. The front end displays pictures. When logging in, roomID and the filled verification code are submitted. The login interface takes out the verification code from redis according to roomId to judge whether it is correct.

This is equivalent to back-end verification.

If you think there is something wrong, you can comment. Thank you

Source code

Front-end part code


<template>
  <div class="login-container">
    <vue-particles
      color="#ffffff"
      :particleOpacity="0.7"
      :particlesNumber="50"
      shapeType="circle"
      :particleSize="4"
      linesColor="#dedede"
      :linesWidth="1"
      :lineLinked="true"
      :lineOpacity="0.4"
      :linesDistance="150"
      :moveSpeed="2"
      :hoverEffect="true"
      hoverMode="grab"
      :clickEffect="true"
      clickMode="push"
    ></vue-particles>
    <el-form ref="loginForm" :model="loginForm" :rules="loginRules" class="login-form" autocomplete="on" label-position="left">
      <div class="title-container">
        <h3 class="title"> Intelligent integrated management system </h3>
      </div>

      <el-form-item prop="username">
        <span class="svg-container">
          <svg-icon icon-class="user" />
        </span>
        <el-input ref="username" v-model="loginForm.username" placeholder=" User name " name="username" type="text" tabindex="1" autocomplete="on" />
      </el-form-item>

      <el-tooltip v-model="capsTooltip" content="Caps lock is On" placement="right" manual>
        <el-form-item prop="password">
          <span class="svg-container">
            <svg-icon icon-class="password" />
          </span>
          <el-input
            :key="passwordType"
            ref="password"
            v-model="loginForm.password"
            :type="passwordType"
            placeholder=" Password "
            name="password"
            tabindex="2"
            autocomplete="on"
            @keyup.native="checkCapslock"
            @blur="capsTooltip = false"
            @keyup.enter.native="handleLogin"
          />
          <span class="show-pwd" @click="showPwd">
            <svg-icon :icon-class="passwordType === 'password' ? 'eye' : 'eye-open'" />
          </span>
        </el-form-item>
      </el-tooltip>
      <el-form-item prop="yzm">
        <span class="svg-container">
          <svg-icon icon-class="password" />
        </span>
        <el-input type="text" v-model="loginForm.verifyCode" maxlength="4" placeholder=" Verification code " />
        <div class="identifyCode" @click="refreshCode">
          <el-image :src="verifyImageUrl"></el-image>
        </div>
      </el-form-item>
      <el-button :loading="loading" type="primary" style="width: 100%; margin-bottom: 30px" @click.native.prevent="handleLogin"> Login </el-button>
    </el-form>
  </div>
</template>

<script>
import { validUsername } from '@/utils/validate'
import Identify from './components/Identify'
import { uuid } from 'vue-uuid'; // uuid object is also exported to things
// outside Vue instance.


export default {
  name: 'Login',
  components: { Identify },
  data() {
    const validateUsername = (rule, value, callback) => {
      if (!validUsername(value)) {
        callback(new Error(' Please enter the correct user name '))
      } else {
        callback()
      }
    }
    const validatePassword = (rule, value, callback) => {
      if (value.length < 6) {
        callback(new Error(' Minimum password 6 Bit '))
      } else {
        callback()
      }
    }
    return {
      loginForm: {
        username: 'admin',
        password: '111111',
        roomId: '',
        verifyCode: ''
      },
      loginRules: {
        username: [{ required: true, trigger: 'blur', validator: validateUsername }],
        password: [{ required: true, trigger: 'blur', validator: validatePassword }]
      },
      passwordType: 'password',
      capsTooltip: false,
      loading: false,
      showDialog: false,
      redirect: undefined,
      otherQuery: {},
      identifyCodes: '1234567890',
      identifyCode: '',
      // verifyImageRoomId: '',
      verifyImageUrl: '',
    }
  },
  watch: {
    $route: {
      handler: function (route) {
        const query = route.query
        if (query) {
          this.redirect = query.redirect
          this.otherQuery = this.getOtherQuery(query)
        }
      },
      immediate: true
    }
  },
  created() {
    // window.addEventListener('storage', this.afterQRScan)
    // this.identifyCode = ''
    // this.makeCode(this.identifyCodes, 4)
    this.refreshCode()
  },
  mounted() {
    if (this.loginForm.username === '') {
      this.$refs.username.focus()
    } else if (this.loginForm.password === '') {
      this.$refs.password.focus()
    }
  },
  destroyed() {
    // window.removeEventListener('storage', this.afterQRScan)
  },
  methods: {
    checkCapslock(e) {
      const { key } = e
      this.capsTooltip = key && key.length === 1 && (key >= 'A' && key <= 'Z')
    },
    showPwd() {
      if (this.passwordType === 'password') {
        this.passwordType = ''
      } else {
        this.passwordType = 'password'
      }
      this.$nextTick(() => {
        this.$refs.password.focus()
      })
    },
    createUuid() {
      let uuidV4 = uuid.v4().replace('-', '').replace('-', '').replace('-', '').replace('-', '')

      this.verifyImageRoomId = uuidV4
      this.verifyImageUrl = '/api/Operator/getCaptchaImage/120/40/' + this.verifyImageRoomId
      console.log(uuidV4)
    },
    handleLogin() {
      this.$refs.loginForm.validate(valid => {
        if (valid) {
          this.loading = true
          this.$store.dispatch('user/login', this.loginForm)
            .then(() => {
              this.$router.push({ path: this.redirect || '/', query: this.otherQuery })
              this.loading = false
            })
            .catch(() => {
              this.loading = false
            })
        } else {
          console.log('error submit!!')
          return false
        }
      })
    },
    getOtherQuery(query) {
      return Object.keys(query).reduce((acc, cur) => {
        if (cur !== 'redirect') {
          acc[cur] = query[cur]
        }
        return acc
      }, {})
    },
    //  Generate random numbers 
    randomNum(min, max) {
      return Math.floor(Math.random() * (max - min) + min)
    },
    //  Switch verification code 
    refreshCode() {
      let uuidV4 = uuid.v4().replace('-', '').replace('-', '').replace('-', '').replace('-', '')

      this.loginForm.roomId = uuidV4
      this.verifyImageUrl = '/api/Operator/getCaptchaImage/120/40/' + this.loginForm.roomId
      console.log(uuidV4)
    },
    //  Generate 4 Bit random verification code 
    makeCode(o, l) {
      for (let i = 0; i < l; i++) {
        this.identifyCode += this.identifyCodes[
          this.randomNum(0, this.identifyCodes.length)
        ]
      }
      console.log(this.identifyCode)
    }
  }
}
</script>

<style lang="scss">
/*  Repair input  Background incongruity   And cursor discoloration  */
/* Detail see https://github.com/PanJiaChen/vue-element-admin/pull/927 */

$bg: #283443;
$light_gray: #fff;
$cursor: #fff;

@supports (-webkit-mask: none) and (not (cater-color: $cursor)) {
  .login-container .el-input input {
    color: $cursor;
  }
}

/* reset element-ui css */
.login-container {
  background: url("~@/assets/background.jpg") no-repeat;
  min-height: 100vh;

  .el-input {
    display: inline-block;
    height: 47px;
    width: 85%;

    input {
      background: transparent;
      border: 0px;
      -webkit-appearance: none;
      border-radius: 0px;
      padding: 12px 5px 12px 15px;
      color: $light_gray;
      height: 47px;
      caret-color: $cursor;

      &:-webkit-autofill {
        box-shadow: 0 0 0px 1000px $bg inset !important;
        -webkit-text-fill-color: $cursor !important;
      }
    }
  }

  .el-form-item {
    border: 1px solid rgba(255, 255, 255, 0.1);
    background: rgba(0, 0, 0, 0.1);
    border-radius: 5px;
    color: #454545;

    .el-form-item__error {
      color: rgb(223, 223, 176);
    }
  }
}
</style>

<style lang="scss" scoped>
$bg: #2d3a4b;
$dark_gray: #889aa4;
$light_gray: #eee;

.login-container {
  min-height: 100%;
  width: 100%;
  background-color: $bg;
  overflow: hidden;

  .login-form {
    position: absolute;
    left: 0;
    right: 0;
    top: 0;
    bottom: 0;
    margin: auto;
    width: 520px;
    max-width: 100%;
    padding: 160px 35px 0;
    margin: 0 auto;
    overflow: hidden;
  }

  .tips {
    font-size: 14px;
    color: #fff;
    margin-bottom: 10px;

    span {
      &:first-of-type {
        margin-right: 16px;
      }
    }
  }

  .svg-container {
    padding: 6px 5px 6px 15px;
    color: $dark_gray;
    vertical-align: middle;
    width: 30px;
    display: inline-block;
  }

  .title-container {
    position: relative;

    .title {
      font-size: 42px;
      color: $light_gray;
      margin: 0px auto 40px auto;
      text-align: center;
      font-weight: bold;
    }
  }

  .show-pwd {
    position: absolute;
    right: 10px;
    top: 7px;
    font-size: 16px;
    color: $dark_gray;
    cursor: pointer;
    user-select: none;
  }
  .identifyCode {
    position: absolute;
    right: 10px;
    top: 5px;
  }

  .thirdparty-button {
    position: absolute;
    right: 0;
    bottom: 6px;
  }

  @media only screen and (max-width: 470px) {
    .thirdparty-button {
      display: none;
    }
  }
}
</style>

Backend interface


        /// <summary>
        ///  Get verification code 
        /// </summary>
        /// <returns></returns>
        [HttpGet("getCaptchaImage/{width:int}/{height:int}/{roomId}")]
        public IActionResult GetCaptchaImage(int width, int height, string roomId)
        {
            Console.WriteLine(roomId);
            //int width = 100;
            //int height = 36;
            var captchaCode = Captcha.GenerateCaptchaCode();
            var result = Captcha.GenerateCaptchaImage(width, height, captchaCode);
            string redisKey = "VerifyCode_" + roomId;
            Startup.redisDb.StringSet(redisKey, captchaCode, new TimeSpan(0, 5, 0));
            Stream s = new MemoryStream(result.CaptchaByteData);
            return new FileStreamResult(s, "image/png");
        }

        /// <summary>
        ///  Login 
        /// </summary>
        /// <returns></returns>
        [HttpPost("login")]
        public ApiResponseData Login(LoginDto loginInfo)
        {
            if (string.IsNullOrWhiteSpace(loginInfo.username))
                return ApiResponse.Error(" User name cannot be empty ");
            if (string.IsNullOrWhiteSpace(loginInfo.password))
                return ApiResponse.Error(" Password cannot be empty ");

            Entity.BaseOperator operInfo = Db
                .Select<BaseOperator>()
                .Where(a => a.OperatorCode == loginInfo.username && a.Password == loginInfo.password.ToLower() && a.Status == 1 && a.IsDel == false).ToOne();
            if (operInfo == null)
                return ApiResponse.Error(" Incorrect username or password ");

            bool verifyResult = Captcha.ValidateCaptchaCode(loginInfo.RoomId, loginInfo.VerifyCode);
            if(verifyResult == false)
                return ApiResponse.Error(" Incorrect verification code ");

            // Rebuild on login token , 1 Users can only be found in 1 Location login 
            string token = System.Guid.NewGuid().ToString().Replace("-", "");
            Db.Update<BaseOperator>(operInfo.OperatorId)
                .Set(a => a.Token, token)
                .ExecuteAffrows();

            dynamic outJson = new ExpandoObject();// Initialization 1 Object that does not contain any members ExpandoObject
            outJson.token = token;

            // Deposit redis
            string redisKey = "UserInfo_" + token;
            Startup.redisDb.StringSet(redisKey, operInfo.OperatorId, new TimeSpan(24, 0, 0));

            return ApiResponse.Succ(outJson);
        }

Related articles: