vue+springboot实现登录验证码(前后端分离)

前言

要实现验证码功能需要明白:
前端:通过img标签获得图片
后端:首先根据前端请求生成图片,然后前端再次处理前端的登录请求

一、流程

1.验证码生成工具类

此工具类用于生成验证码图片

package com.pp.educational_management_system.config;import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Random;public class VerificationCode {private int width = 100;// 生成验证码图片的宽度private int height = 30;// 生成验证码图片的高度private String[] fontNames = { "宋体", "楷体", "隶书", "微软雅黑" };private Color bgColor = new Color(255, 255, 255);// 定义验证码图片的背景颜色为白色private Random random = new Random();private String codes = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";private String text;// 记录随机字符串/*** 获取一个随意颜色** @return*/private Color randomColor() {int red = random.nextInt(150);int green = random.nextInt(150);int blue = random.nextInt(150);return new Color(red, green, blue);}/*** 获取一个随机字体** @return*/private Font randomFont() {String name = fontNames[random.nextInt(fontNames.length)];int style = random.nextInt(4);int size = random.nextInt(5) + 24;return new Font(name, style, size);}/*** 获取一个随机字符** @return*/private char randomChar() {return codes.charAt(random.nextInt(codes.length()));}/*** 创建一个空白的BufferedImage对象** @return*/private BufferedImage createImage() {BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);Graphics2D g2 = (Graphics2D) image.getGraphics();g2.setColor(bgColor);// 设置验证码图片的背景颜色g2.fillRect(0, 0, width, height);return image;}public BufferedImage getImage() {BufferedImage image = createImage();Graphics2D g2 = (Graphics2D) image.getGraphics();StringBuffer sb = new StringBuffer();for (int i = 0; i < 4; i++) {String s = randomChar() + "";sb.append(s);g2.setColor(randomColor());g2.setFont(randomFont());float x = i * width * 1.0f / 4;g2.drawString(s, x, height - 8);}this.text = sb.toString();drawLine(image);return image;}/*** 绘制干扰线** @param image*/private void drawLine(BufferedImage image) {Graphics2D g2 = (Graphics2D) image.getGraphics();int num = 5;for (int i = 0; i < num; i++) {int x1 = random.nextInt(width);int y1 = random.nextInt(height);int x2 = random.nextInt(width);int y2 = random.nextInt(height);g2.setColor(randomColor());g2.setStroke(new BasicStroke(1.5f));g2.drawLine(x1, y1, x2, y2);}}public String getText() {return text;}public static void output(BufferedImage image, OutputStream out) throws IOException {ImageIO.write(image, "JPEG", out);}
}

2.图片请求

前端:

<img class="verifyCodeImg" :src="imgUrl" @click="resetImg">

imgUrl在数据区定义(new Date()生成随机事件用于更换验证码,防止浏览器缓存):

imgUrl:"http://localhost:9000/home/verifyCode?time="+new Date(),

resetImg方法用于点击更换验证码 图片

resetImg(){this.imgUrl = "http://localhost:9000/home/verifyCode?time="+new Date();},

后端:
生成验证码图片返回到前端,并且将验证码的code存在session中

 @GetMapping("/verifyCode")public void verifyCode(HttpServletRequest request, HttpServletResponse resp) throws IOException {VerificationCode code = new VerificationCode();BufferedImage image = code.getImage();String text = code.getText();HttpSession session = request.getSession(true);session.setAttribute("verify_code", text);VerificationCode.output(image,resp.getOutputStream());}

3.后端进行登录验证

前后端分离项目此处有坑!!!!!!
前端获取验证码的时候将code存在了session中,在登录验证的时候只需要将用户输入的验证码code和session中的code比较就行了。但是因为是前后端分离的项目,每次前端的ajax请求都是新的,每次请求的sessionID都不一样,所以每次使用的session不是同一个,以至于登录时session里面的值为null。
解决方式
在vue的main.js中配置axios,让每次请求都带上浏览器的cookie,这样后端使用的session就是同一个了。

 axios.defaults.withCredentials = true

源代码

前端:

 <template><div class="login_container"><img :src="imgSrc" width="100%" height="100%" /><!--登录块--><div class="login_box"><!--表单区域--><el-formref="loginFromRef":rules="loginRules":model="loginFrom"class="login_from"label-width="0px"><h3 class="headline">教学管理系统</h3><!--用户名--><el-form-item prop="username"><el-inputv-model="loginFrom.username"prefix-icon="iconfont icon-denglu"placeholder="用户名"></el-input></el-form-item><!--密码--><el-form-item prop="password"><el-inputv-model="loginFrom.password"prefix-icon="iconfont icon-mima"type="password"placeholder="密码"></el-input></el-form-item><el-form-item prop="verifyCode"><el-col :span="16"><el-inputv-model="loginFrom.verifyCode"prefix-icon="el-icon-message"placeholder="验证码"class="verifyCode"></el-input></el-col><el-col :span="8"><img class="verifyCodeImg" :src="imgUrl" @click="resetImg"></el-col></el-form-item><!--按钮--><el-form-item class="btn"><el-button type="primary" @click="login">登录</el-button><!-- <el-button type="info" @click="resetLoginForm">重置</el-button> --></el-form-item></el-form></div></div>
</template>
<script>
export default {data() {return {//表单数据imgUrl:"http://localhost:9000/home/verifyCode?time="+new Date(),loginFrom: {username: "admin",password: "123456",verifyCode:"",},//验证对象loginRules: {//校验用户名username: [{ required: true, message: "请输入用户名称", trigger: "blur" }, //必填项验证{min: 5,max: 12,message: "长度在 5 到 12 个字符",trigger: "blur",}, //验证长度],//校验密码password: [{ required: true, message: "请输入用户密码", trigger: "blur" }, //必填项验证{min: 6,max: 10,message: "长度在 6 到 10 个字符",trigger: "blur",}, //验证长度],},imgSrc: require("../assets/bg.png"),};},methods: {resetLoginForm() {//重置表单内容this.$refs.loginFromRef.resetFields();},resetImg(){this.imgUrl = "http://localhost:9000/home/verifyCode?time="+new Date();},login() {//登录请求this.$refs.loginFromRef.validate(async (validate) => {//判断是否验证成功if (!validate) return;const { data: res } = await this.$http.post("home/login",this.loginFrom);if (res.status == "200") {this.$message.success("登陆成功");window.sessionStorage.setItem("user", res.id);const {data:res1} = await this.$http.get("menus",{params:{id:window.sessionStorage.getItem("user"),}});window.sessionStorage.setItem("menu",window.JSON.stringify(res1.menus));window.sessionStorage.setItem("token", res.token);//跳转页面this.$router.push({ path: "/home" });} else if(res.status == "400"){this.$message.error("用户名或密码错误");}else if(res.status == "404"){this.$message.error("账号未激活,请联系管理员");}else{this.$message.error("验证码输入错误");this.imgUrl = "http://localhost:9000/home/verifyCode?time="+new Date();}});},},
};
</script>
<style lang="less" scoped>
.login_container {background-color: #2b4b6b;height: 100%;
}
.login_box {background: rgba(78, 102, 112, 0.1);width: 450px;height: 330px;border-radius: 5px;position: absolute;left: 50%;top: 50%;transform: translate(-50%, -50%);
}
.btn {width: 100%;
}
.login_from {position: absolute;bottom: 0%;width: 100%;padding: 0 10px;box-sizing: border-box;.verifyCode {width:"60%",}.verifyCodeImg {margin-top: 5px;margin-left: 10px;height: 30px;width:"60%",}
}
.el-button {margin-left: 10%;width: 80%;
}
.el-form-item {margin-left: 10%;width: 80%;
}
.headline {font-size: 20px;color: white;margin-left: 35%;
}
</style>

后端:

package com.pp.educational_management_system.controller;import com.alibaba.fastjson.JSON;
import com.pp.educational_management_system.anotation.Log;
import com.pp.educational_management_system.config.VerificationCode;
import com.pp.educational_management_system.domain.User;
import com.pp.educational_management_system.service.impl.ShiroService;
import com.pp.educational_management_system.utils.MD5Utils;
import org.springframework.web.bind.annotation.*;import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;@RestController
@RequestMapping("/home")
public class ShiroController {public static User user;private final ShiroService shiroService;public ShiroController(ShiroService shiroService) {this.shiroService = shiroService;}/*** 登录*/@Log("登录")@RequestMapping("/login")public String login(@RequestBody User us, HttpServletRequest request, HttpServletResponse resp) {Map<String, Object> result = new HashMap<>();if(request.getSession(true).getAttribute("verify_code")==null||!us.getVerifyCode().toUpperCase().equals(request.getSession(true).getAttribute("verify_code").toString().toUpperCase())){result.put("status", 300);result.put("msg", "验证码错误");return JSON.toJSONString(result);}String username = us.getUsername();String password = us.getPassword();//用户信息User user = shiroService.getUserByName(username);//账号不存在、密码错误if (user == null || !user.getPassword().equals(MD5Utils.generatePassword(password))) {result.put("status", 400);result.put("msg", "账号或密码有误");}else if(user.getState()==0){result.put("status", 404);result.put("msg", "账号未激活,请联系管理员");}else {this.user = user;//生成token,并保存到数据库result = shiroService.createToken(user.getId());result.put("status", 200);result.put("msg", "登陆成功");result.put("id",user.getId());}String res = JSON.toJSONString(result);return res;}/*** 得到验证码图片* @param request* @param resp* @throws IOException*/@GetMapping("/verifyCode")public void verifyCode(HttpServletRequest request, HttpServletResponse resp) throws IOException {VerificationCode code = new VerificationCode();BufferedImage image = code.getImage();String text = code.getText();HttpSession session = request.getSession(true);session.setAttribute("verify_code", text);VerificationCode.output(image,resp.getOutputStream());}/*** 退出*/@RequestMapping("/logout")public Map<String, Object> logout(@RequestHeader("token")String token) {Map<String, Object> result = new HashMap<>();shiroService.logout(token);result.put("status", 200);result.put("msg", "您已安全退出系统");return result;}}

vue+springboot实现登录验证码(前后端分离)相关推荐

  1. Java网络商城项目 SpringBoot+SpringCloud+Vue 网络商城(SSM前后端分离项目)十六(商品排序,Thymeleaf快速入门,商品详情页的展示)

    Java网络商城项目 SpringBoot+SpringCloud+Vue 网络商城(SSM前后端分离项目)十六(商品详情页的展示) 一.商品排序 1.完善页面信息 这是用来做排序的,默认按照综合排序 ...

  2. Java网络商城项目 SpringBoot+SpringCloud+Vue 网络商城(SSM前后端分离项目)二十二(下单和微信支付)

    Java网络商城项目 SpringBoot+SpringCloud+Vue 网络商城(SSM前后端分离项目)二十(下单) 0.学习目标 会调用订单系统接口 实现订单结算功能 实现微信支付功能 1.订单 ...

  3. Java网络商城项目 SpringBoot+SpringCloud+Vue 网络商城(SSM前后端分离项目)十四(Spring Data Elasticsearch,将数据添加到索引库)

    Java网络商城项目 SpringBoot+SpringCloud+Vue 网络商城(SSM前后端分离项目)十四(Spring Data Elasticsearch,将数据添加到索引库) 一.创建El ...

  4. java计算机毕业设计基于springboot+vue+elementUI的实验室管理系统(前后端分离)

    项目介绍 科技水平一直是体现一个国家强弱的重要标志,而科技的一点诞生地是实验室,如果能够更好的对实验室进行管理是很多实验室管理人员一直研究的一个问题.只有更加科学和合理化的利用实验室才能够更好的让科技 ...

  5. (2022)Springboot+vue3项目开发前后端分离书法图书管理Coun

    项目地址:https://github.com/KKJava1/Coun Coun是基于Springboot+vue3 项目采用了前后端分离技术:后端采用 springBoot 基本框架,数据库连接池 ...

  6. Java权限管理|基于springBoot+springSecurity+jwt实现前后端分离用户权限认证

    基于springBoot+springSecurity+jwt实现前后端分离用户权限认证 1. 项目说明   主要基于前后端分离情况下用户权限认证, 当用户登录认证成功后,每个用户会获取到自己的tok ...

  7. 计算机课程设计-基于ssm+vue的物资管理系统(前后端分离)-物资出库入库管理系统java代码

    计算机课程设计-基于ssm+vue的物资管理系统(前后端分离)-物资出库入库管理系统java代码 注意:该项目只展示部分功能,如需了解,评论区咨询即可. 作者:IT跃迁谷 1.开发环境 开发语言:Ja ...

  8. Vue:前端体系与前后端分离

    Vue:前端体系与前后端分离 概述 介绍 ​ Vue(读音/viu/,类似于 view)是一套用于构建用户界面的渐进式框架,发布干 2014 年 2 月. 与其它大型框架不同的是,Vue 被设计为可以 ...

  9. 推荐一些基于vue.js的uni-app框架前后端分离的一些毕设项目

    一些基于vue.js的uni-app框架前后端分离的一些项目 下面这些课题都可以作为基于vue的前后端分类的毕设项目 下面的这些项目都可以演示的是微信小程序 下面的这些项目都可以转成h5项目 下面的这 ...

  10. Springboot + Spring Security 实现前后端分离登录认证及权限控制

    Spring Security简介 Spring Security 是 Spring 家族中的一个安全管理框架,实际上,在 Spring Boot 出现之前,Spring Security 就已经发展 ...

最新文章

  1. 2021年广东赛区线上比赛高校组合点-五邑大学
  2. Android官方开发文档Training系列课程中文版:构建第一款安卓应用之入门指南
  3. idea插件开发(02)---相关概念介绍
  4. 浙大计算机基础知识题1,浙大作业1计算机基础知识题.docx
  5. EasyPR车牌识别学习总结
  6. 存储过程 while is null_java 自动化 使用存储过程构造测试数据
  7. java compiler.run_eclipse build path与java Compiler
  8. python制作印刷体数据集:数字符号数据集(字符串转图片)
  9. 苹果mac误删文件怎样快速找回?
  10. 九万字的JavaWeb学习记录,从入门到入坟,更近一步
  11. keil兼容51单片机和arm
  12. java雷霆战机项目收获_java实习项目_雷霆战机
  13. 2019年nodejs凉了吗?凉到什么程度了?
  14. VLDB 历年最佳论文汇总
  15. 电子元器件B2B商城系统授信大额支付,精细化B2B平台管理
  16. C/C++常用计时函数
  17. 在html中超链接的标记是,在HTML代码中,超链接元素的标记是什么?
  18. SSL数字证书下载流程是怎么样的
  19. 用uefi安装linux系统安装win7系统分区,UEFI模式下Win/Linux双系统安装
  20. 论坛介绍 | COSCon'22 物联网(IoT)

热门文章

  1. java语言程序设计第三版电子书百度云_Java语言程序设计(基础篇)(原书第10版) 完整版 中文pdf扫描版[259MB]梁勇...
  2. Effective Modern C++42招独家技巧助你改善C++11和C++14的高效用法笔记
  3. android音乐播放器app源码
  4. (java)五大常用算法
  5. 数字电子技术课程设计用单片机实现数字电子钟
  6. 如何做好产品需求设计和开发
  7. 如何在虚拟机安装windows server 2003
  8. GTF - Great Teacher Friedman
  9. Linux内核移植操作步骤
  10. MySQL安装包下载地址(含所有版本)