SpringBoot+Vue+Token实现登录验证码校验

目录

流程简介

效果图

依赖

后端代码

验证码生成

验证码校验

前段代码


流程简介

借助hutool工具绘制二维码,用token存储验证码及过期时间,后端在响应头中放入token。前端将token存入vuex中,登陆时拿取。

效果图

依赖

  <!-- hutool -->
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.3.3</version>
        </dependency>
    
        <!-- jwt -->
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt</artifactId>
            <version>0.9.1</version>
        </dependency>

后端代码

后端主要分为两个流程:验证码生成,验证码校验。生成验证码借助Hutool工具,使用Jwt工具类加密存储、校验

验证码生成

controller

  @RequestMapping(value ="/verify")
    public void getVerify(HttpServletResponse response, HttpServletRequest request){
        response.setContentType("image/jpeg");
        //不缓存
        response.setHeader("Pragma","No-cache");
        response.setHeader("Cache-Control","no-cache");
        response.setDateHeader("Expire",0);
        RandomValidateCode code = new RandomValidateCode();
        try{
            code.creatRandCode(request,response);
            log.info("验证码生成成功");
            //下面方法是自己用java工具类绘制的验证码
           // code.getRandcode(request,response);
        }catch (Exception e){
            log.error("验证码生成失败");
        }
    }

绘制验证码

    public void creatRandCode(HttpServletRequest request, HttpServletResponse response) throws IOException {
        //hutool工具类 宽度 高度 位数 线条数
        LineCaptcha lineCaptcha = CaptchaUtil.createLineCaptcha(120, 40, 4, 15);
        lineCaptcha.write(response.getOutputStream());
        Long currentTimeMillis = System.currentTimeMillis();
        String signRandom = JwtUtils.signRandom(lineCaptcha.getCode(), currentTimeMillis);
        response.setHeader("CODEKEY", signRandom);
        response.setHeader("Access-Control-Expose-Headers", "CODEKEY");
    }

jwtUtils

@ConfigurationProperties(prefix = "Demo.jwt")

使用注解读取配置(验证码过期时间这里直接写到代码中了)

     private String secret;
    private long expire;
    private String header;
    public static final long RANDOM_TIME = 60*1000;
  

 /**
     * 放入验证码以及过期时间
     * 加密盐为 YunMengQingYanLou##Demo
     * @param code
     * @param currentTime
     * @return
     */
    public static  String signRandom(String code,Long currentTime){
        String token = null;
        Date expireDate = new Date(currentTime+RANDOM_TIME);
        token =  Jwts.builder()
                .claim("code",code)
                .claim("currentTime",currentTime)
                .setExpiration(expireDate)
                .signWith(SignatureAlgorithm.HS512, "YunMengQingYanLou##Demo")
                .compact();
        return token;
    }

验证码校验

只展示验证码相关逻辑

 @Override
    public SysResult login(LoginParam loginParam, HttpServletResponse response, HttpServletRequest request) throws IllegalAccessException {
        /**检查参数是否合法
         * 使用jwt生产token返回前端
         * token放入redis中  redis token user 设置过期时间
         */
        String account = loginParam.getAccount();
        String password = loginParam.getPassword();
        String verifyCode = loginParam.getVerifyCode();
        //获取验证码
        String codekey = request.getHeader("Codekey");
        try {
            Claims claim = JwtUtils.getClaim(codekey);
            String code = claim.get("code").toString();
            Long currentTime = (Long) JwtUtils.getClaim(codekey).get("currentTime");
            Long randomTime = currentTime + (Long) JwtUtils.RANDOM_TIME;
            log.info("验证码时间" + randomTime);
            long nowTime = System.currentTimeMillis();
            if (randomTime < nowTime) {
                return SysResult.fail("验证码已失效");
            }
            if (!verifyCode.equals(code)) {
                return SysResult.fail("验证码不正确");
            }
        } catch (Exception e) {
            log.error(e.getMessage());
            throw new IllegalAccessException("系统异常");
        }
         password = DigestUtils.md5DigestAsHex((password + slat).getBytes());
        SysUser sysUser = sysuserService.findUser(account);
        Assert.notNull(sysUser, "没有该用户");
        String pwd = sysUser.getPassword();
        if (!password.equals(pwd)) {
            return SysResult.fail("密码不正确");
        }
        String jwt = jwtUtils.generateToken(sysUser.getId());
        //将jwt输送Header
        response.setHeader("Authorization", jwt);
        response.setHeader("Access-control-Expose-Headers", "Authorization");
        return SysResult.success(sysUser);

    }

JwtUtils获得claim 注意加密盐一致

 /**
     * 校验 出错返回为空
     * @param token
     * @return
     */
    public static Claims getClaim(String token) {
        try {
            return Jwts.parser()
                    .setSigningKey("YunMengQingYanLou##Demo")
                    .parseClaimsJws(token)
                    .getBody();
        }catch (Exception e){
            log.error("Token解析异常 ", e);
            return null;
        }
    }

后端代码至此全部完毕

前段代码

前段代码逻辑主要是请求后端接口接受验证码信息,放入store中,登录时拿取并放入请求头

<template>
    <div class="background">
        <div class="log">
            <div class="title">YunMeng</div>
            <el-form :model="ruleForm" :rules="rules" ref="ruleForm" label-width="100px" class="demo-ruleForm">
                <el-form-item label="用户名" prop="account">
                    <el-input v-model="ruleForm.account"></el-input>
                </el-form-item>

                <el-form-item label="密码" prop="password">
                    <el-input type="password" v-model="ruleForm.password"></el-input>
                </el-form-item>

                <el-form-item label="验证码" prop="verifyCode" class="veriftyCode">
                    <el-input type="verifyCode" style="width: 50%;" v-model="ruleForm.verifyCode"></el-input>
                    <img :src="verifyurl" alt="单击刷新" ref="verifyImg" class="verifyImg" @click="getVerifty()" />
                </el-form-item>

                <el-form-item>
                    <el-button type="primary" @click="submitForm('ruleForm')" style="width: 110px">登录</el-button>
                    <el-button @click="resetForm('ruleForm')" style="width: 120px">重置</el-button>
                </el-form-item>

            </el-form>
        </div>
    </div>
</template>

获取验证码Js

    mounted() {
            this.getVerifty()
        },
        methods: {
            getVerifty() {
                const _this = this;
                _this.$axios.get("/verify", {
                    responseType: 'blob'
                }).then(res => {
                    if (res) {
                        const verifycode = res.headers['codekey'];
                        _this.verifyurl = window.URL.createObjectURL(new Blob([res.data]))
                        _this.$store.commit("SET_VERIFTY", verifycode);
                    } else {
                        this.$message.error("获取验证码失败")
                    }
                })
            },

store/index.js

只看verifty相关代码即可

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

export default new Vuex.Store({
  state: {
    verifty:'',
    token:'',
    userInfo:JSON.parse(sessionStorage.getItem("userInfo")),
    menu:JSON.parse(sessionStorage.getItem("menu"))
  },
  mutations: {
      SET_VERIFTY:(state,verifty) =>{
        state.verifty = verifty
        sessionStorage.setItem("verifty",verifty)

      },
      
    SET_MENU:(state,menu) =>{
      state.menu = menu
      sessionStorage.setItem("menu",JSON.stringify(menu))

    },
    //数据的改变
    SET_TOKEN: (state,token) =>{
      state.token = token
      localStorage.setItem("token",token)
    },
    SET_USERINFO: (state,userInfo) =>{
      state.userInfo = userInfo
      sessionStorage.setItem("userInfo",JSON.stringify(userInfo))
      //不能存字符串
    },
    REMOVE_INFO:(state) =>{
      state.token = '';
       state.verifty = '';
      state.userInfo = {};
      state.menu='';
      localStorage.setItem("token",'')
      sessionStorage.setItem("userInfo", JSON.stringify(''))
      sessionStorage.setItem("menu",JSON.stringify(''))
      sessionStorage.setItem("verifty",'')
    }
  },
  getters:{
    getUser: state =>{
      return state.userInfo
    },
    getToken:state=>{
      return state.token
    },
    getMenu:state => {
      return state.menu
    },
    getVerifty:state => {
      return state.verifty
    }

  },
  actions: {
  },
  modules: {
  }
})

登录JS

submitForm(formName) {
                this.$refs[formName].validate((valid) => {
                    if (valid) {
                        const _this = this;
                        _this.$axios.post("/login", _this.ruleForm, {
                            headers: {
                                "Codekey":sessionStorage.getItem("verifty")
                            }
                        }).then(res => {
                            console.log(res)
                            if (res.data.status == 200) {
                                // //存储(共享)全局变量jwt和userInfo
                                const jwt = res.headers['authorization'];
                                const userInfo = res.data.data
                                const admin = userInfo.admin;
                                const avator = userInfo.avatar;
                                _this.$store.commit("SET_TOKEN", jwt);
                                _this.$store.commit("SET_USERINFO", userInfo)
                                console.log(userInfo)
                                _this.$router.push({
                                    path: "/home",
                                    query: {
                                        adminId: admin,
                                        pit: avator
                                    }
                                })
                            } else {
                                this.$message.error(res.data.msg)
                                this.getVerifty();
                            }
                        })
                    } else {
                        console.log('error submit!!');
                        return false;
                    }
                });
            },

前段完整代码

<template>
    <div class="background">
        <div class="log">
            <div class="title">YunMeng</div>
            <el-form :model="ruleForm" :rules="rules" ref="ruleForm" label-width="100px" class="demo-ruleForm">
                <el-form-item label="用户名" prop="account">
                    <el-input v-model="ruleForm.account"></el-input>
                </el-form-item>

                <el-form-item label="密码" prop="password">
                    <el-input type="password" v-model="ruleForm.password"></el-input>
                </el-form-item>

                <el-form-item label="验证码" prop="verifyCode" class="veriftyCode">
                    <el-input type="verifyCode" style="width: 50%;" v-model="ruleForm.verifyCode"></el-input>
                    <img :src="verifyurl" alt="单击刷新" ref="verifyImg" class="verifyImg" @click="getVerifty()" />
                </el-form-item>

                <el-form-item>
                    <el-button type="primary" @click="submitForm('ruleForm')" style="width: 110px">登录</el-button>
                    <el-button @click="resetForm('ruleForm')" style="width: 120px">重置</el-button>
                </el-form-item>

            </el-form>
        </div>
    </div>
</template>

<script>
    export default {
        name: "Login",
        data() {
            return {
                verifyurl: '',
                ruleForm: {
                    account: '',
                    password: '',
                    verifyCode: ''
                },
                rules: {
                    account: [{
                            required: true,
                            message: '请输入用户名',
                            trigger: 'blur'
                        },
                        {
                            min: 3,
                            max: 15,
                            message: '长度在 3 到 15 个字符',
                            trigger: 'change'
                        }
                    ],
                    password: [{
                        required: true,
                        message: '请输入密码',
                        trigger: 'blur'
                    }],
                    verifyCode: [{
                        required: true,
                        message: '请输入验证码',
                        trigger: 'blur'
                    }],
                }
            };
        },
        mounted() {
            this.getVerifty()
        },
        methods: {

            getVerifty() {
                const _this = this;
                _this.$axios.get("/verify", {
                    responseType: 'blob'
                }).then(res => {
                    if (res) {
                        const verifycode = res.headers['codekey'];
                        _this.verifyurl = window.URL.createObjectURL(new Blob([res.data]))
                        _this.$store.commit("SET_VERIFTY", verifycode);
                    } else {
                        this.$message.error("获取验证码失败")
                    }
                })

            },
            submitForm(formName) {
                this.$refs[formName].validate((valid) => {
                    if (valid) {
                        const _this = this;
                        _this.$axios.post("/login", _this.ruleForm, {
                            headers: {
                                "Codekey":sessionStorage.getItem("verifty")
                            }
                        }).then(res => {
                            console.log(res)
                            if (res.data.status == 200) {
                                // //存储(共享)全局变量jwt和userInfo
                                const jwt = res.headers['authorization'];
                                const userInfo = res.data.data
                                const admin = userInfo.admin;
                                const avator = userInfo.avatar;
                                _this.$store.commit("SET_TOKEN", jwt);
                                _this.$store.commit("SET_USERINFO", userInfo)
                                console.log(userInfo)
                                _this.$router.push({
                                    path: "/home",
                                    query: {
                                        adminId: admin,
                                        pit: avator
                                    }
                                })
                            } else {
                                this.$message.error(res.data.msg)
                                this.getVerifty();
                            }
                        })
                    } else {
                        console.log('error submit!!');
                        return false;
                    }
                });
            },
            resetForm(formName) {
                this.$refs[formName].resetFields();
            }
        }
    }
</script>

<style scoped>

    .verifyImg {
        width: 96px;
        height: 40px;
        border-radius: 8px;
        vertical-align: middle;
        margin-left: 12px;
    }

    .background {
      
        background: url("../assets/35.jpg");
        width: 100%;
        height: 100%;
        position: fixed;
        background-size: 100% 100%;
    }

    .title {
        font-size: 70px;
        font-family: 黑体;
        color: black;
        margin-left: 30px;
        padding-top: 20px;
        text-align: center;
    }

    .log {
        background: rgba(255, 255, 255, 0.6);
        box-shadow: 0 5px 30px 0 rgba(0, 0, 0, 0.2);
        position: absolute;
        left: 50%;
        top: 50%;
        transform: translate(-50%, -50%);
        width: 650px;
        height: 400px;
        border-radius: 20px;
    }

    .demo-ruleForm {
        margin-top: 30px;
        margin-left: 40px;
        max-width: 500px;
    }
</style>

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值