携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第5天,点击查看活动详情
需求来源:
应该平台项目演示会后,老板提出来的,因为看到平台的登录,总觉得少了点东西,说是要加上,那就加吧
准备时间:
时间蛮长的,架构组的同事提了2周,一直都没有给说什么做,因为在参与其他紧急项目救火。大概上周抽了1天时间做了相关开发。
内心独白:
觉得这个功能可有可无,对于ToB的平台,要这干什么。安全考虑还是。。。
不想了,问了一圈都没说出个什么
技术准备:
大概知道怎么弄,但是做之前习惯性的搜索搜索相关技术,就去翻了一遍掘金,发现大部分的验证码功能都是canvas前端自己绘制,封装成一个组件,传入一些参数,然后作为一个公共组件去调用。我觉得也应该这么做。
沟通结果:
与架构侧的同事沟通后,他更期望主要功能在后端实现,一来不太相信前端,二来是考虑安全问题。我这暴脾气,一听就来气,什么不相信前端的东西。我想了想,前端组件实现2套,根据配置切换,一可以切换前端canvas绘制图形验证码也可以远端获取。但是现阶段,没多少时间和精力,不能搞的太麻烦,先实现第一版。
最近决定后端来生成验证码,主要工作在后端,前端事情相对较少,这样出问题容易甩出去。以安全为主考虑为重(决策盾牌)
功能定位:
放在了业务侧的 businessComponents 目录下,业务组件 Security
组件实现:
<template>
<div class="code" @click="refreshCode" title="刷新验证码">
<img class="verification-code" :src="verificationUrl" alt="验证码" />
</div>
</template>
<script setup>
import { ref } from 'vue'
import { Service } from "@basic-library";
// 验证码请求地址
const verificationUrl = ref()
/**
* 点击刷新
*/
const refreshCode = async (params) => {
verificationUrl.value = Service.parse('queryCaptcha')
}
defineExpose({
refreshCode,
});
</script>
<style lang="scss" scoped>
.verification-code {
vertical-align: middle;
cursor: pointer;
}
</style>
Service.parse()
方法,主要是框架层提供,解析和拼装请求url地址的,因为接口返回的是图片的二进制流,直接扔给image的src,这样比较直接些
更好的方式:
使用http请求的方式,返回的二进制图片流,转换后,最终成为base64的图片塞给image标签去
let bytes = new Uint8Array(data);
let storeData = "";
let len = bytes.byteLength;
for (let i = 0; i < len; i++) {
storeData += String.fromCharCode(bytes[i]);
}
this.imgUrl = "data:image/png;base64," + window.btoa(storeData);
这种方式,http的请求头,需要更改
responseType必须是arrayBuffer,json是不行的
后面根据情况,在去修改吧,先搞简单的版本。
上面只是说了验证码图片组件的实现,下面描述下场景使用
登录页面使用:
// 验证码区域
<el-form-item prop="captcha" label="">
<div class="captcha-text">
<el-input placeholder="请输入验证码" v-model="userForm.captcha" @keyup.enter="submitForm()"></el-input>
</div>
<div class="captcha-code">
<Security ref="SecurityRefs"></Security>
</div>
</el-form-item>
import { Security } from '@businessComponents'
/**
* 加载验证码
*/
const loadVerifyCode = (params) => {
SecurityRefs.value.refreshCode()
userForm.captcha = ''
}
/**
* @desc 登录
* @param {Object} NO
*/
const jumpLogin = async () => {
setConfig()
const { accountName, password, captcha } = userForm
const result = await Service.useHttp({
name: "loginService",
headers: { captcha }
},{
accountName,
password,
});
loading.value = false
// 刷新验证码
loadVerifyCode()
if (result?.success) {
if(!loginAfterService(result)) return
LoginLoader.redirectApp('/')
}
};
onMounted(async () => {
// 加载验证码
loadVerifyCode()
});
上述代码中的大体实现思路已经有了,代码中有部分:
- 框架提供:
Service.useHttp
发送请求
LoginLoader.redirectApp
应用跳转,默认当前应用首页 - 页内方法:
loginAfterService
请求成功后,登录数据校验部分,不合规的无法登录
setConfig
登录前做相关数据配置
写完,午睡了
补充:
中午测试妹子,来找到我,这个验证码输入框,输入中文后报错,我默默的打开了控制台,看到了
fetch-like-axios
的 httpInstance.interceptors.response.use
报错,ISO什么错来着,应该协议格式问题,默认是charset=utf-8
解决方式:
验证码输入框,禁止输入中文和控制,进行控制
onkeyup="value=value.replace(/[^\w\.\/]/ig,'')"
<el-input placeholder="请输入验证码"
v-model="userForm.captcha"
onkeyup="value=value.replace(/[^\w\.\/]/ig,'')"
@keyup.enter="submitForm()"
maxlength=20>
</el-input>