linux修改 dns配置檔案/etc/resolv.conf重啟之後自動還原的解決方法
阿新 • • 發佈:2021-06-18
目錄
- 概述
- 部分原理
- 原始碼
概述
網上的前端驗證碼邏輯總感覺不安全,驗證碼建議還是使用後端配合驗證。
如果產品確定可以上網的話,就可以使用騰訊,百度等第三方驗證,對接方便。但是產品可能內網部署,就必須自己寫了。
本文章就是基於這一點來實現的。
前端驗證碼顯示一個圖片,後端生成圖片。
部分原理
1.前端呼叫生端獲取圖片時,傳入一個roomID,後端生成一個4位驗徵碼,放入redis中。然後生成一個圖片返回。
2.前端顯示圖片,登入時將roomID和填寫的驗證碼,一併提交,登入介面根據roomId從redis中取出驗證碼判斷是否正確。
這樣就相當於後端驗證了。
大家覺得有問題什麼,可以進行評論。謝謝。
原始碼
前端部分程式碼
<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">智慧綜合管理系統</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="使用者名稱" 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="密碼" 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"> &mvZxZoViDlt;svg-icon icon-class="password" /> </span> <el-input type="text" v-model="loginForm.verifyCode" maxlength="4" placeholder="驗證碼" /> <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">登入</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('請輸入正確的使用者名稱')) } else { callback() } } const validatePassword = (rule,callback) => { if (value.length < 6) { callback(new Error('密碼最少6位')) } else { callback() } } return { loginForm: { username: 'admin',password: '111111',roomId: '',verifyCode: '' },loginRules: { username: [{ required: true,trigger: 'blur',validator: validateUsername }],password: [{ required: true,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.usernammvZxZoViDe.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('-','') 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 },{}) },// 生成隨機數 randomNum(min,max) { return Math.floor(Math.random() * (max - min) + min) },// 切換驗證碼 refreshCode() { let uuidV4 = uuid.v4().replace('-','') this.loginForm.roomId = uuidV4 this.verifyImageUrl = '/api/Operator/getCaptchaImage/120/40/' + this.loginForm.roomId console.log(uuidV4) },// 生成四位隨機驗證碼 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"> /* 修復input 背景不協調 和游標變色 */ /* 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,0.1); background: rgba(0,0.1); border-radius: 5px; color: #454545; .el-form-item__error { color: rgb(223,223,176); } } } </style> <style lang="scss" scoped> $bg: #2d3a4b; $dwww.cppcns.comark_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; mvZxZoViD 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>
後端介面
/// <summary> /// 獲取驗證碼 /// </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 ne程式設計客棧w FileStreamResult(s,"image/png"); } /// <summary> /// 登入 /// </summary> /// <returns></returns> [HttpPost("login")] public ApiResponseData Login(LoginDto loginInfo) { if (string.IsNullOrWhiteSpace(loginInfo.username)) return ApiResponse.Error("使用者名稱不能為空"); if (string.IsNullOrWhiteSpace(loginInfo.password)) return ApiResponse.Error("密碼不能為空"); 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("使用者名稱或者密碼不正確"); bool verifyResult = Captcha.ValidateCaptchaCode(loginInfo.RoomId,loginInfo.VerifyCode); if(verifyResult == false) return ApiResponse.Error("驗證碼不正確"); //登入時重新生成token,一個使用者只能在一個地方登入 string token = System.Guid.NewGuid().ToString().Replace("-",""); Db.Update<BaseOperator>(operInfo.OperatorId) .Set(a => a.Token,token) .ExecuteAffrows(); dynamic outjson = new ExpandoObject();//初始化一個不包含任何成員的ExpandoObject outJson.token = token; //存入redis string redisKey = "UserInfo_" + token; Startup.redisDb.StringSet(redisKey,operInfo.OperatorId,new TimeSpan(24,0)); return ApiResponse.Succ(outJson); }
到此這篇關於asp.net core配合vue實現後端驗證碼邏輯的文章就介紹到這了,更多相關asp.net core驗證碼 內容請搜尋我們以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援我們!