欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Vue實現(xiàn)圖片驗證碼生成

 更新時間:2022年03月04日 08:29:37   作者:游人耶  
這篇文章主要為大家詳細(xì)介紹了Vue實現(xiàn)圖片驗證碼生成,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下

圖片驗證碼主要用于注冊,登錄等提交場景中,目的是防止腳本進(jìn)行批量注冊、登錄、灌水,相比不帶圖片驗證的安全度有所提高,不過目前也有自動識別圖片驗證碼的程序出現(xiàn),基本都是付費(fèi)識別,隨之又出現(xiàn)了滑動驗證,選取正確選項驗證等更加安全的驗證方式。但圖片驗證碼碼仍用于大部分網(wǎng)站中。

一、前端圖片驗證碼生成

前端邏輯大體就是進(jìn)行圖形繪制,取幾個隨機(jī)數(shù)放入圖片中,加入干擾,進(jìn)行驗證

1.創(chuàng)建驗證碼組件identify.vue

<template>
? <div class="s-canvas" style="display: inline">
? ? <canvas id="s-canvas" :width="contentWidth" :height="contentHeight"></canvas>
? </div>
</template>
<script>
export default{
? name: 'SIdentify',
? props: {
? ? identifyCode: { // 默認(rèn)注冊碼
? ? ? type: String,
? ? ? default: '1234'
? ? },
? ? fontSizeMin: { // 字體最小值
? ? ? type: Number,
? ? ? default: 25
? ? },
? ? fontSizeMax: { // 字體最大值
? ? ? type: Number,
? ? ? default: 35
? ? },
? ? backgroundColorMin: { // 驗證碼圖片背景色最小值
? ? ? type: Number,
? ? ? default: 200
? ? },
? ? backgroundColorMax: { // 驗證碼圖片背景色最大值
? ? ? type: Number,
? ? ? default: 220
? ? },
? ? dotColorMin: { // 背景干擾點(diǎn)最小值
? ? ? type: Number,
? ? ? default: 60
? ? },
? ? dotColorMax: { // 背景干擾點(diǎn)最大值
? ? ? type: Number,
? ? ? default: 120
? ? },
? ? contentWidth: { // 容器寬度
? ? ? type: Number,
? ? ? default: 117
? ? },
? ? contentHeight: { // 容器高度
? ? ? type: Number,
? ? ? default: 32
? ? }
? },
? methods: {
? ? // 生成一個隨機(jī)數(shù)
? ? randomNum (min, max) {
? ? ? return Math.floor(Math.random() * (max - min) + min)
? ? },
?
? ? // 生成一個隨機(jī)的顏色
? ? randomColor (min, max) {
? ? ? let r = this.randomNum(min, max)
? ? ? let g = this.randomNum(min, max)
? ? ? let b = this.randomNum(min, max)
? ? ? return 'rgb(' + r + ',' + g + ',' + b + ')'
? ? },
?
? ? drawPic () {
? ? ? let canvas = document.getElementById('s-canvas')
? ? ? let ctx = canvas.getContext('2d')
? ? ? ctx.textBaseline = 'bottom'
? ? ? // 繪制背景
? ? ? ctx.fillStyle = '#e6ecfd'
? ? ? ctx.fillRect(0, 0, this.contentWidth, this.contentHeight)
? ? ? // 繪制文字
? ? ? for (let i = 0; i < this.identifyCode.length; i++) {
? ? ? ? this.drawText(ctx, this.identifyCode[i], i)
? ? ? }
? ? ? this.drawLine(ctx)
? ? ? this.drawDot(ctx)
? ? },
?
? ? drawText (ctx, txt, i) {
? ? ? ctx.fillStyle = this.randomColor(50, 160) // 隨機(jī)生成字體顏色
? ? ? ctx.font = this.randomNum(this.fontSizeMin, this.fontSizeMax) + 'px SimHei' // 隨機(jī)生成字體大小
? ? ? let x = (i + 1) * (this.contentWidth / (this.identifyCode.length + 1))
? ? ? let y = this.randomNum(this.fontSizeMax, this.contentHeight - 5)
? ? ? var deg = this.randomNum(-30, 30)
? ? ? // 修改坐標(biāo)原點(diǎn)和旋轉(zhuǎn)角度
? ? ? ctx.translate(x, y)
? ? ? ctx.rotate(deg * Math.PI / 180)
? ? ? ctx.fillText(txt, 0, 0)
? ? ? // 恢復(fù)坐標(biāo)原點(diǎn)和旋轉(zhuǎn)角度
? ? ? ctx.rotate(-deg * Math.PI / 180)
? ? ? ctx.translate(-x, -y)
? ? },
?
? ? drawLine (ctx) {
? ? ? // 繪制干擾線
? ? ? for (let i = 0; i < 4; i++) {
? ? ? ? ctx.strokeStyle = this.randomColor(100, 200)
? ? ? ? ctx.beginPath()
? ? ? ? ctx.moveTo(this.randomNum(0, this.contentWidth), this.randomNum(0, this.contentHeight))
? ? ? ? ctx.lineTo(this.randomNum(0, this.contentWidth), this.randomNum(0, this.contentHeight))
? ? ? ? ctx.stroke()
? ? ? }
? ? },
?
? ? drawDot (ctx) {
? ? ? // 繪制干擾點(diǎn)
? ? ? for (let i = 0; i < 30; i++) {
? ? ? ? ctx.fillStyle = this.randomColor(0, 255)
? ? ? ? ctx.beginPath()
? ? ? ? ctx.arc(this.randomNum(0, this.contentWidth), this.randomNum(0, this.contentHeight), 1, 0, 2 * Math.PI)
? ? ? ? ctx.fill()
? ? ? }
? ? }
? },
? watch: {
? ? identifyCode () {
? ? ? this.drawPic()
? ? }
? },
? mounted () {
? ? this.drawPic()
? }
}
</script>

2.父組件

前端生成驗證碼的校驗是自己生成驗證碼,用戶輸入的值和生成的驗證碼字符串進(jìn)行比對校驗的,校驗沒有走后端,在真正發(fā)送請求到后端的時候也是不將驗證碼傳給后臺的。

<template>
? ? <div slot="content" class="reg-body">
? ? ? <div class="main-content">
? ? ? ? <el-form ref="form" :model="form" :rules="rules" label-width="125px" label-position="left">
? ? ? ? ? <el-form-item label="驗證碼" class="my-item" prop="code">
? ? ? ? ? ? <el-input
? ? ? ? ? ? ? v-model.trim="form.code"
? ? ? ? ? ? ? placeholder="請輸入正確的驗證碼"
? ? ? ? ? ? ? size="small"
? ? ? ? ? ? ? style="width: 200px "
? ? ? ? ? ? />
? ? ? ? ? ? <span class="login-code" style="position: absolute; right: 0; top: 4px; left: 257px">
? ? ? ? ? ? ? <Identify :identifyCode="identifyCode"></Identify>
? ? ? ? ? ? </span>
? ? ? ? ? ? <span
? ? ? ? ? ? ? class="el-icon-refresh-right"
? ? ? ? ? ? ? style="position: absolute; ?left: 394px; top: 13px; cursor: pointer"
? ? ? ? ? ? ? @click="refreshCode"
? ? ? ? ? ? />
? ? ? ? ? </el-form-item>
? ? ? ? </el-form>
? ? ? ? <div style="text-align: center">
? ? ? ? ? <el-button
? ? ? ? ? ? v-if="form.agreement"
? ? ? ? ? ? style="background:#6BC6A1; color: white; border-radius:2px; width: 200px; height: 30px; line-height: 5px; border: none;margin-bottom: 10px"
? ? ? ? ? ? @click="submitForm()"
? ? ? ? ? ? :loading="loading"
? ? ? ? ? >提交</el-button>
? ? ? ? </div>
? ? ? </div>
? ? </div>
</template>
?
<script>
import Identify from "./identify";
export default {
? name: "Reg",
? mixins: [region],
? components: {Identify },
? data() {
? ? return {
? ? ? formSetting: {
? ? ? ? contentWidth: 340,
? ? ? },
? ? ? form: {
? ? ? ? logoUrl: "",
? ? ? ? licenseUrl: "",
? ? ? ? description: [],
? ? ? ? account: "",
? ? ? ? name: "",
? ? ? },
? ? ? code:this.$route.query.code,
? ? ? identifyCodes: "1234567890abcdefjhijklinopqrsduvwxyz",
? ? ? identifyCode: "",
? ? ? picList: [],
? ? ? props: { label: "name", value: "id", children: "children" },
? ? ? rules: {
? ? ? ? code: [{ required: true, message: "請輸入驗證碼", trigger: "change" }],
? ? ? },
? ? ? formList: [],
? ? };
? },
? created() {
? ? // this.getAllDict()
? },
? mounted() {
? ? this.getRegion();
? ? // 初始化驗證碼
? ? this.identifyCode = "";
? ? this.makeCode(this.identifyCodes, 4);
? ? localStorage.setItem("code", this.code);
? },
? methods: {
? ? openHtml() {
? ? ? this.visible = true;
? ? },
? ? //刷新驗證碼
? ? refreshCode() {
? ? ? this.identifyCode = "";
? ? ? this.makeCode(this.identifyCodes, 4);
? ? },
? ? //生成驗證上的隨機(jī)數(shù),驗證碼中的數(shù)從identifyCodes中取,
? ? makeCode(o, l) {
? ? ? for (let i = 0; i < l; i++) {
? ? ? ? this.identifyCode += this.identifyCodes[
? ? ? ? ? this.randomNum(0, this.identifyCodes.length)
? ? ? ? ];
? ? ? }
? ? },
? ? //生成隨機(jī)數(shù),這里是生成
? ? //Math.random()方法返回大于等于0小于1的一個隨機(jī)數(shù)
? ? //隨機(jī)數(shù) = Math.floor(Math.random() * 可能的總數(shù) + 第一個可能的值)
? ? randomNum(min, max) {
? ? ? return Math.floor(Math.random() * (max - min) + min);
? ? },
? ? // 提交表單
? ? submitForm() {
? ? ? this.$refs["form"].validate((valid) => {
? ? ? ? if (valid) {
? ? ? ? ? if (this.loading) {
? ? ? ? ? ? return;
? ? ? ? ? }
? ? ? ? ? this.loading = true;
? ? ? ? ? this.submit();
? ? ? ? } else {
? ? ? ? ? return false;
? ? ? ? }
? ? ? });
? ? },
? ? submit: async function () {
? ? ? if (this.form.code.toLowerCase() !== this.identifyCode.toLowerCase()) {
? ? ? ? this.$msg({ type: "error", message: "請?zhí)顚懻_驗證碼" });
? ? ? ? this.refreshCode();
? ? ? ? this.loading = false;
? ? ? ? return;
? ? ? } else {
? ? ? ? //驗證碼校驗成功就可以調(diào)接口提交表單了
? ? },
? },
};
</script>

二、后端生成圖片驗證碼

后臺思路很,利用BufferedImage類創(chuàng)建一張圖片,再用Graphics對圖片進(jìn)行繪制(生成隨機(jī)字符,添加噪點(diǎn),干擾線)即可。

package com.hengtiansoft.gxrc.base.util;
?
import com.hengtiansoft.gxrc.common.constant.MagicNumConstant;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
?
import javax.imageio.ImageIO;
import java.awt.Font;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
?
@Slf4j
@Component
public class ImgCaptchaUtil {
?
?
? ? private Random random = new Random();
? ? /**
? ? ?* 驗證碼的寬
? ? ?*/
? ? private final int width = 160;
? ? /**
? ? ?* 驗證碼的高
? ? ?*/
? ? private final int height = 40;
? ? /**
? ? ?* 驗證碼的干擾線數(shù)量
? ? ?*/
? ? private final int lineSize = 30;
? ? /**
? ? ?* 驗證碼詞典
? ? ?*/
? ? private final String randomString = "0123456789abcdefghijklmnopqrstuvwxyz";
?
? ? /**
? ? ?* 獲取字體
? ? ?* @return
? ? ?*/
? ? private Font getFont() {
? ? ? ? return new Font("Times New Roman", Font.ROMAN_BASELINE, MagicNumConstant.FORTY);
? ? }
?
? ? /**
? ? ?* 獲取顏色
? ? ?* @param fc
? ? ?* @param bc
? ? ?* @return
? ? ?*/
? ? private Color getRandomColor(int fc, int bc) {
?
? ? ? ? int fcc = Math.min(fc, MagicNumConstant.TWO_HUNDRED_FIFTY_FIVE);
? ? ? ? int bcc = Math.min(bc, MagicNumConstant.TWO_HUNDRED_FIFTY_FIVE);
?
? ? ? ? int r = fcc + random.nextInt(bcc - fcc - MagicNumConstant.SIXTEEN);
? ? ? ? int g = fcc + random.nextInt(bcc - fcc - MagicNumConstant.FOURTEEN);
? ? ? ? int b = fcc + random.nextInt(bcc - fcc - MagicNumConstant.TWELVE);
?
? ? ? ? return new Color(r, g, b);
? ? }
?
? ? /**
? ? ?* 繪制干擾線
? ? ?* @param g
? ? ?*/
? ? private void drawLine(Graphics g) {
? ? ? ? int x = random.nextInt(width);
? ? ? ? int y = random.nextInt(height);
? ? ? ? int xl = random.nextInt(MagicNumConstant.TWENTY);
? ? ? ? int yl = random.nextInt(MagicNumConstant.TEN);
? ? ? ? g.drawLine(x, y, x + xl, y + yl);
? ? }
?
? ? /**
? ? ?* 獲取隨機(jī)字符
? ? ?* @param num
? ? ?* @return
? ? ?*/
? ? private String getRandomString(int num) {
? ? ? ? int number = num > 0 ? num : randomString.length();
? ? ? ? return String.valueOf(randomString.charAt(random.nextInt(number)));
? ? }
?
? ? /**
? ? ?* 繪制字符串
? ? ?* @param g
? ? ?* @param randomStr
? ? ?* @param i
? ? ?* @return
? ? ?*/
? ? private String drawString(Graphics g, String randomStr, int i) {
? ? ? ? g.setFont(getFont());
? ? ? ? g.setColor(getRandomColor(MagicNumConstant.ONE_HUNDRED_EIGHT, MagicNumConstant.ONE_HUNDRED_NINETY));
? ? ? ? String rand = getRandomString(random.nextInt(randomString.length()));
? ? ? ? String randomString = randomStr + rand;
? ? ? ? g.translate(random.nextInt(MagicNumConstant.THREE), random.nextInt(MagicNumConstant.SIX));
? ? ? ? g.drawString(rand, MagicNumConstant.FORTY * i + MagicNumConstant.TEN, MagicNumConstant.TWENTY_FIVE);
? ? ? ? return randomString;
? ? }
?
? ? /**
? ? ?* 生成隨機(jī)圖片,返回 base64 字符串
? ? ?* @param
? ? ?* @return
? ? ?*/
? ? public Map<String, String> getImgCodeBaseCode(int length) {
? ? ? ? Map<String, String> result = new HashMap<>();
? ? ? ? // BufferedImage類是具有緩沖區(qū)的Image類,Image類是用于描述圖像信息的類
? ? ? ? BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_BGR);
? ? ? ? Graphics g = image.getGraphics();
? ? ? ? g.fillRect(0, 0, width, height);
? ? ? ? // 獲取顏色
? ? ? ? g.setColor(getRandomColor(MagicNumConstant.ONE_HUNDRED_FIVE, MagicNumConstant.ONE_HUNDRED_EIGHTY_NINE));
? ? ? ? // 獲取字體
? ? ? ? g.setFont(getFont());
? ? ? ? // 繪制干擾線
? ? ? ? for (int i = 0; i < lineSize; i++) {
? ? ? ? ? ? drawLine(g);
? ? ? ? }
?
? ? ? ? // 繪制隨機(jī)字符
? ? ? ? String randomCode = "";
? ? ? ? for (int i = 0; i < length; i++) {
? ? ? ? ? ? randomCode = drawString(g, randomCode, i);
? ? ? ? }
? ? ? ? g.dispose();
?
? ? ? ? result.put("imgCode", randomCode);
?
? ? ? ? String base64Code = "";
? ? ? ? try {
? ? ? ? ? ? //返回 base64
? ? ? ? ? ? ByteArrayOutputStream bos = new ByteArrayOutputStream();
? ? ? ? ? ? ImageIO.write(image, "PNG", bos);
?
? ? ? ? ? ? byte[] bytes = bos.toByteArray();
? ? ? ? ? ? Base64.Encoder encoder = Base64.getEncoder();
? ? ? ? ? ? base64Code = encoder.encodeToString(bytes);
?
? ? ? ? } catch (Exception e) {
? ? ? ? ? ? log.debug(e.getMessage());
? ? ? ? }
? ? ? ? result.put("data", "data:image/png;base64," + base64Code);
? ? ? ? return result;
? ? }
?
}

后臺生成圖片base64,和一個唯一的key(通過這個key判斷是哪張圖片),后臺可以通過接口傳給前端圖片base64和key,前端輸入驗證碼,傳給后臺key和驗證碼去校驗驗證。

package com.hengtiansoft.gxrc.base.service.impl;
?
import com.hengtiansoft.gxrc.base.service.ImgCaptchaService;
import com.hengtiansoft.gxrc.base.util.ImgCaptchaUtil;
import com.hengtiansoft.gxrc.common.constant.MagicNumConstant;
import com.hengtiansoft.gxrc.common.entity.exception.BusinessException;
import com.hengtiansoft.gxrc.common.redis.RedisOperation;
import com.hengtiansoft.gxrc.common.util.UUIDUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
?
import java.util.Map;
?
/**
?* @Description:
?* @Author: wu
?* @CreateDate: 2020/11/11 17:17
?*/
@Service
public class ImgCaptchaServiceImpl implements ImgCaptchaService {
?
? ? private static final String IMG_CAPTCHA = "imgCaptcha:";
?
? ? @Autowired
? ? private RedisTemplate<String, Object> redisTemplate;
?
? ? @Autowired
? ? private ImgCaptchaUtil imgCaptchaUtil;
?
? ? @Override
? ? public Map<String, String> getImgCaptcha() {
? ? ? ? RedisOperation redisOperation = new RedisOperation(redisTemplate);
? ? ? ? Map<String, String> map = imgCaptchaUtil.getImgCodeBaseCode(MagicNumConstant.FOUR);
? ? ? ? String uuid = UUIDUtils.createUUID();
? ? ? ? redisOperation.set(IMG_CAPTCHA + uuid, map.get("imgCode"));
? ? ? ? redisOperation.expire(IMG_CAPTCHA + uuid, MagicNumConstant.THIRTY_THOUSAND);
? ? ? ? map.remove("imgCode");
? ? ? ? map.put("key", uuid);
? ? ? ? return map;
? ? }
?
? ? @Override
? ? public void checkImgCaptcha(String code, String key) {
? ? ? ? RedisOperation redisOperation = new RedisOperation(redisTemplate);
? ? ? ? String captcha = redisOperation.get(IMG_CAPTCHA + key);
? ? ? ? if (ObjectUtils.isEmpty(captcha) || !StringUtils.equals(captcha, code)) {
? ? ? ? ? ? throw new BusinessException("驗證碼錯誤");
? ? ? ? }
? ? ? ? redisOperation.del(IMG_CAPTCHA + key);
? ? }
}

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • vue中el-select中多選回顯數(shù)據(jù)后沒法重新選擇和更改的解決

    vue中el-select中多選回顯數(shù)據(jù)后沒法重新選擇和更改的解決

    本文主要介紹了vue中el-select中多選回顯數(shù)據(jù)后沒法重新選擇和更改解決,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2024-01-01
  • Vue3?$emit用法指南(含選項API、組合API及?setup?語法糖)

    Vue3?$emit用法指南(含選項API、組合API及?setup?語法糖)

    這篇文章主要介紹了Vue3?$emit用法指南,使用?emit,我們可以觸發(fā)事件并將數(shù)據(jù)傳遞到組件的層次結(jié)構(gòu)中,本文通過實例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下
    2022-07-07
  • Vue2.4+新增屬性.sync、$attrs、$listeners的具體使用

    Vue2.4+新增屬性.sync、$attrs、$listeners的具體使用

    這篇文章主要介紹了Vue2.4+新增屬性.sync、$attrs、$listeners的具體使用,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-03-03
  • Vue實現(xiàn)附件上傳功能

    Vue實現(xiàn)附件上傳功能

    這篇文章主要為大家詳細(xì)介紹了Vue實現(xiàn)附件上傳功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-05-05
  • vue使用vue-video-player插件播放視頻的步驟講解

    vue使用vue-video-player插件播放視頻的步驟講解

    在最近的項目中有一個視頻播放的功能,在之前的項目中沒有接觸過類似的功能,第一次接觸,把具體操作步驟一下,這篇文章主要給大家介紹了關(guān)于vue使用vue-video-player插件播放視頻的相關(guān)資料,需要的朋友可以參考下
    2022-12-12
  • 詳解Vue如何實現(xiàn)顏色選擇與調(diào)色板功能

    詳解Vue如何實現(xiàn)顏色選擇與調(diào)色板功能

    顏色選擇和調(diào)色板是Web開發(fā)中常用的功能,Vue作為一個流行的JavaScript框架,可以方便地實現(xiàn)顏色選擇和調(diào)色板功能,本文講講如何在Vue中進(jìn)行顏色選擇和調(diào)色板吧
    2023-06-06
  • vue截圖轉(zhuǎn)base64轉(zhuǎn)文件File異步獲取方式

    vue截圖轉(zhuǎn)base64轉(zhuǎn)文件File異步獲取方式

    這篇文章主要介紹了vue截圖轉(zhuǎn)base64轉(zhuǎn)文件File異步獲取方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-03-03
  • vue使用H5的audio標(biāo)簽問題

    vue使用H5的audio標(biāo)簽問題

    這篇文章主要介紹了vue使用H5的audio標(biāo)簽問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-12-12
  • vue項目多租戶環(huán)境變量的設(shè)置

    vue項目多租戶環(huán)境變量的設(shè)置

    本文主要介紹了vue項目多租戶環(huán)境變量的設(shè)置,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-04-04
  • Vue3的10種組件通信方式總結(jié)

    Vue3的10種組件通信方式總結(jié)

    組件是vue.js最強(qiáng)大的功能之一,而組件實例的作用域是相互獨(dú)立的,這就意味著不同組件之間的數(shù)據(jù)無法相互引用,這篇文章主要給大家介紹了關(guān)于Vue3的10種組件通信方式的相關(guān)資料,文中通過實例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2022-03-03

最新評論