日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > vue >内容正文

vue

UKEY开发,vue+websocket实现用户登录UKEY认证

發布時間:2024/8/1 vue 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 UKEY开发,vue+websocket实现用户登录UKEY认证 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

首先,在開始開發之前,先了解一下UKEY的用戶登錄流程,我前面整理了一些登錄的流程:

點這里查看登錄流程:傳送門

?

OK,了解了登錄流程,我們來開始看看在vue中是怎么樣進行實際的開發的。

首先你需要在導航收尾中初始化websocket的連接:

router.beforeEach((to, from, next) => {// 初始化后后能夠監聽UKEY拔插事件store.dispatch({type: "startUkey"}); }

補充說明:為了安全性,我們的需求是這樣的:用戶只有在UKEY插入的情況下才能夠登錄后臺,用戶拔出UKEY后就注銷該用戶。所以需要在導航守衛中初始化UKEY。

?

接下來,我們需要編寫websocket邏輯處理,我將所有的websocket處理都放在vuex的action里面,下面是action的全部代碼:

import { SIGN_OUT } from "@/store/modules/user/constant";import axios from "@/modules/axios"; import route from "@/router"; import { user as userServer } from "@/modules/server-url";var s_pnp = ""; if (!s_pnp) {s_pnp = new WebSocket("ws://127.0.0.1:4006/xxx","usbkey-protocol"); }const getRandomCode = async (commit,callback) => {try {// 獲取簽名使用的隨機數const data = await axios.post(userServer.getRandomCode);commit({type: "SET_RANDOM_CODE",playload: {code: data}});callback({succ_status: 3,msg: "獲取簽名隨機數成功",data: {random_code_status: true,random_code: data}});} catch (err) {if (err && err.code) {callback({err_status: 6,msg: "獲取簽名隨機數失敗",data: {random_code_status: false,random_code: ""}})}} };const listenUkey = (dispatch, commit, state, request = { type: 0, pin_code: "", callback: () => {}}) => {try {var Path = ""; // 路徑var insert_status = 0; // ukey的拔插事件會執行兩次,防止第二次執行if (request.type != 0) { // 不是初始化流程let socketStatus = s_pnp.GetWebsocketStatus();if (socketStatus == 0) {setTimeout(() => {s_pnp.send(JSON.stringify({FunName: "ResetOrder"}));},500);} else {s_pnp.send(JSON.stringify({FunName: "ResetOrder"}));}}s_pnp.Socket_UK.onopen = function () {s_pnp.send(JSON.stringify({FunName: "ResetOrder"})); // 這里調用ResetOrder將計數清零,這樣,消息處理處就會收到0序號的消息,通過計數及序號的方式,從而生產流程};// 在使用事件插撥時,注意,一定不要關掉Sockey,否則無法監測事件插撥s_pnp.onmessage = function (Msg) {let PnpData = JSON.parse(Msg.data);if (PnpData.type == "PnpEvent") { // 如果是插撥事件處理消息if (PnpData.IsIn) { // 監聽到插入if (insert_status === 1) return;console.log("ukey插入");insert_status = 1;s_pnp.send(JSON.stringify({FunName: "ResetOrder"}));} else { // 監聽到拔出if (insert_status === 2) return;console.log("ukey拔出");insert_status = 2;if (typeof request.callback == "function") {request.callback({err_status: 2,msg: NO_UKEY});}if (route.history.current.path == "/") return false;// 檢測到UKEY拔出,退出登錄return dispatch(SIGN_OUT);}}if (PnpData.type == "Process") { // 如果是事件處理流程var order = PnpData.order;if (state.serve_random_code.length == 0) {getRandomCode(commit,request.callback);} else {if (typeof request.callback == "function") {request.callback({succ_status: 3,msg: "獲取簽名隨機數成功",data: {random_code_status: true,random_code: state.serve_random_code}});}}if (order == 0) {s_pnp.send(JSON.stringify({FunName: "FindPort",start: start})); // 查找加密鎖} else if (order == 1) {if ( PnpData.LastError != 0 ) {if (typeof request.callback == "function") {request.callback({err_status: 2,msg: "未檢測到UKEY"});}return false;}// 已插入UKEYPath = PnpData.return_value; // 獲得返回的UK的路徑s_pnp.send(JSON.stringify({FunName: "GetChipID",Path:Path})); // 獲取鎖唯一ID} else if (order == 2) { // 獲取到鎖IDif ( PnpData.LastError != 0 ) {if (typeof request.callback == "function") {request.callback({err_status: 3,msg: "獲取鎖ID失敗"});}return false;}if (typeof request.callback == "function") {request.callback({succ_status: 1,msg: "獲取鎖ID成功。",data: {ukey_id: PnpData.return_value}});}// 返回設置在鎖中的用戶名s_pnp.send(JSON.stringify({FunName: "GetSm2UserName",Path:Path}));} else if (order == 3) { // 獲取到用戶身份if ( PnpData.LastError != 0 ) {if (typeof request.callback == "function") {request.callback({err_status: 4,msg: "獲取用戶名失敗。"});}request.callback({err_status: 4,msg: "獲取用戶名失敗。"});return false;}if (typeof request.callback == "function") {request.callback({succ_status: 2,msg: "獲取用戶身份成功。",data: {account: PnpData.return_value}});}}if (request.type == 1) { // 驗證Pin碼if (order == 3) {// 對數據進行簽名,驗證pin碼,在內部會驗證pin碼,驗證正確后才能夠簽名,驗證錯誤后則pin碼錯誤s_pnp.send(JSON.stringify({FunName: "YtSign",SignMsg:state.SignMsg,Pin:state.Pin,Path:Path}));} else if (order == 4) {if ( PnpData.LastError != 0 ) {request.callback({err_status: 5,msg: "Pin碼驗證失敗。"});return false;}request.callback({succ_status: 4,msg: "簽名成功",data: {autograph: PnpData.return_value}});commit({type: "SET_PIN_CODE",playload: {code: request.pin_code}});}}}};s_pnp.onerror = function () {console.log("連接錯誤");};s_pnp.onclose = function () {console.log("連接關閉");};} catch (e) {console.error(e.name + ": " + e.message);return false;} };export default {startUkey({ dispatch, commit, state }, request = { type: 0, callback: (res) => {} }) {// 不兼容IE10以下的瀏覽器if (navigator.userAgent.indexOf("MSIE") > 0 && !navigator.userAgent.indexOf("opera") > -1) {commit({type: "SET_IE10_UNDER",playload: {status: true,msg: UNDER_IE10}});request.callback({err_status: 1,msg: UNDER_IE10});return false;}try {listenUkey(dispatch, commit, state, request);} catch (err) {console.error(err);}} };

是不是一頭霧水?別急這里就給你說明一下,首先websocket的生命周期要了解一下的:

事件事件處理程序描述
openSocket.onopen連接建立時觸發
messageSocket.onmessage客戶端接收服務端數據時觸發
errorSocket.onerror通信發生錯誤時觸發
closeSocket.onclose連接關閉時觸發

我們這里主要用到的是message事件,在我的理解中message事件就是一個監聽,而目標返回一次信息,就執行一次message事件,而UKEY是以輪詢的方式進行通訊的,所以每次執行send函數后,都會觸發message事件,每次都觸發相同的函數時我們就需要根據狀態來區分流程了,UKEY自身就有一套流程的記錄,也就是上面代碼中的order屬性了,每執行一個send都會創建一個流程,order就會加一。

因為登錄是需要用戶輸入Pin碼的,不能一套流程直接走完,需要中途用戶觸發驗證來進行驗證Pin碼的流程,所以這里我通過type來標識是不是用戶主動觸發的驗證Pin碼流程。

用戶觸發驗證Pin碼的代碼如下:

<template><div ref="signInDom" class="sign-in" ><el-form :show-message="true":model="form":rules="rules":ref="formName"label-width="15px"class="sign-in-form"@submit.native.prevent="submitForm"><div class="sign-in-logo"><img :src="logoSrc" alt=""></div><div class="sign-in-info"><span>{{ tips }}</span></div> <div class="sign-in-form-item"><i class="form-input-icon icon-tubiao211"/><el-form-item prop="account"><el-input ref="accountInput"v-model="form.account"type="text" placeholder="用戶名" disabled="disabled" auto-complete="off" /></el-form-item></div><div class="sign-in-form-item"><i class="form-input-icon icon-mima1"/><el-form-item prop="password"><el-input ref="passwordInput"v-model="form.password" type="password" placeholder="密碼" auto-complete="off"@keyup.enter="enterEvent"/></el-form-item></div> <div class="sign-in-form-item"><i class="form-input-icon icon-mima1"/><el-form-item prop="pinCode"><el-input ref="pinCodeInput"v-model="form.pinCode" type="password" placeholder="pin碼" auto-complete="off"@keyup.enter="enterEvent"/></el-form-item></div><div v-if="ukey_id.length>0" class="sign-in-ukey"><span>當前UKEY的ID為:</span><span>{{ ukey_id }}</span></div></el-form></div> </template><style lang="less"> @import "./index"; </style><script> import logoSrc from "./images/sign-in.png"; import { mapActions, mapState, mapMutations } from "vuex"; import axios from "@/modules/axios"; import { user } from "@/modules/server-url"; import { NO_UKEY, UNDER_IE10, LOAD_UKEY_START } from "@/store/modules/ukey/constant";export default {name: "SignIn",data() {const validateAccount = (rule, value, callback) => {if (value === "") {callback(new Error("用戶名不能為空"));}else {callback();}};const validateCode = (rule, value, callback) => {if (value === "") {callback(new Error("驗證碼不能為空"));} else if (value.length !== 4) {callback(new Error("請輸入4位驗證碼"));} else {callback();}};const validatePinCode = (rule, value, callback) => {if (value === "") {callback(new Error("Pin碼不能為空"));}else {callback();}};return {logoSrc,formName: "signInForm",// 表單數據form: {account: "",password: "",pinCode: "",randomNum: "",dataSign: "",checked: true},// 驗證規則rules: {account: [{ required: true, validator: validateAccount, trigger: "blur" }],password: [{ required: true, message: "密碼不能為空", trigger: "change" }],pinCode: [{ required: true, message: "pin碼不能為空", trigger: "change" }]},codeForm: {smsCode: ""},codeRules: {smsCode: [{ required: true, validator: validateCode, trigger: "blur" }]},pinCodeRules: {pinCode: [{ required: true, validator: validatePinCode, trigger: "blur" }]},/** 正在登陸 */isSignIn: false,/** 或驗證碼冷卻中 */codeIsLoading: false,/** 驗證碼發送中 */codeIsSending: false,/** 驗證碼倒計時 */countTime: 180,countId: null,codeInnerText: "重新發送",// 展示驗證碼輸入窗口showCode: false,tips: "",codeStatus: "fail",phone: "",ukey_id: "", // ukey的唯一IDshowDownload: false, // 是否顯示下載提示ukey_error: false,randomCodeLoad: true, // 簽名隨機數加載中showNotify: false // 是否顯示右下角提示};},computed: {...mapState({user: state => state.user}),loginStatus() {if (this.randomCodeLoad) {return true;}if (this.isSignIn) {return true;} else {return false;}},loginStatusMsg() {if (this.randomCodeLoad) {return "加載中";}if (this.isSignIn) {return "登錄中";} else {return "登錄";}},getTips() {return this.$store.state.user.signMsg;},getIsSignedOut: state => state.user.isSignedOut,/** 是否需要短信驗證 */getSmsState: state => {return {needSmsVerify: state.user.needSmsVerify,codeStatus: state.user.codeStatus};}},watch: {getIsSignedOut(isSignedOut) {/** 退出登錄成功 */if (isSignedOut) {this.initForminitForm();}},/** 設置提示信息 */getTips(tips) {this.tips = tips;}},mounted() {this.initForminitForm();this.LOAD_UKEY_START({type: 0, callback: this.wesocketRes});},methods: {...mapActions([SIGN_IN,LOAD_UKEY_START]),...mapMutations([SIGN_IN_FULLFILLED]),/** 輸入框初始化和聚焦 */initForminitForm() {const accountsHistory = getItem("signInHistory");if (accountsHistory) {this.form.account = accountsHistory.pop();this.focusInput("passwordInput");} else {this.focusInput("accountInput");}},/** 表單提交 */submitForm() {if (this.isSignIn) return;this.isSignIn = true;this.$refs[this.formName].validate(async valid => {if (valid) {this.LOAD_UKEY_START({type: 1, pin_code: this.form.pinCode, callback: this.wesocketRes});} else {this.isSignIn = false;return false;}});},async wesocketRes(res) {// console.log("wesocket返回值",res);if (res.err_status) {this.tips = res.msg;this.ukey_error = true;this.isSignIn = false;if (res.err_status == 2) {this.tips = res.msg;this.showDownload = true;this.ukey_id = "";this.showTipsNotify();}if (res.err_status == 6) {this.form.randomNum = res.data.random_code;}}if (res.succ_status) {this.tips = "";this.ukey_error = false;if (res.succ_status == 1) {this.ukey_id = res.data.ukey_id;}if (res.succ_status == 2) {this.showDownload = false;this.form.account = res.data.account;}if (res.succ_status == 3) { // 簽名隨機數this.randomCodeLoad = false;this.form.randomNum = res.data.random_code;}if (res.succ_status == 4) {this.form.dataSign = res.data.autograph;if (!this.judgeUkeyStatus()) return;// 簽名成功后才能進行登錄let formData = Object.assign({},this.form);delete formData.pinCode; // 不能把PIN碼放在網絡中傳輸let result = await this.SIGN_IN(formData, this.$router);this.isSignIn = false;if (result && result.needSmsVerify) {this.showCode = true;await this.$nextTick();// 如果需要驗證碼登陸,獲取驗證碼this.getCode();this.phone = this.user.user.phone;const { codeStatus } = result;// 需要短信驗證碼 code === 6 超過短信發送次數 code === 0 正確if (+codeStatus === 0 || +codeStatus === 11) {this.codeStatus = "success";} else {this.codeStatus = "fail";}}}}},/* 檢查鎖狀態 */judgeUkeyStatus() {if (this.ukey_error) {return false;}if (this.form.randomNum.length == 0) {return false;}if (this.form.dataSign.length == 0) {return false;}return true;},/** 重置表單 */resetForm() {if (!this.showCode && (this.form.account || this.form.password)) {if (this.$refs[this.formName] !== undefined) {this.$refs[this.formName].resetFields();}}},// 顯示下載驅動提示showTipsNotify() {let that = this;if (that.showNotify) return false;that.showNotify = true;this.$notify({title: "提示",dangerouslyUseHTMLString: true,duration: 6000,position: "bottom-right",message: `<div><div style='margin-bottom: 10px;'>只有在UKEY插入并且Pin碼正確后才能登陸哦。如果提示檢測不到UKEY,請確認是否下載并安裝了瀏覽器驅動。</div><div><a style='color: #03A9F4;' href='#'>立即下載驅動</a></div></div>`,onClose: () => {that.showNotify = false;}});},resetCodeButton() {this.clearCounter();this.codeIsLoading = false;},clearCounter() {this.codeIsLoading = false;if (this.counterId) {clearInterval(this.counterId);this.counterId = null;}}} }; </script>

?如代碼所示,我使用了一個回調函數來處理UKEY函數的執行結果,提示信息或者認證狀態。

?

總結

以上是生活随笔為你收集整理的UKEY开发,vue+websocket实现用户登录UKEY认证的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。