前后分离springboot

前后端分离开发中的验证码问题

2019-11-24  本文已影响0人  陶然然_niit

1.环境和工具

2.方案描述

3.注意点

4.关键代码

import java.util.Random;

/**
 * @author mq_xu
 * @ClassName StringUtil
 * @Description 字符串工具类
 * @Date 2019/11/14
 * @Version 1.0
 **/
public class StringUtil {

   private final static int MAX = 4;

    public static String getRandomString() {
        StringBuilder stringBuilder = new StringBuilder();
        Random random = new Random();
        int index;
        //生成四位随机字符
        for (int i = 0; i < MAX; i++) {
            //随机生成0、1、2三个整数,代表数字字符、大写字母、小写字母,保证验证码的组成比较正态随机
            index = random.nextInt(3);
            //调用本类封装的私有方法,根据编号获得对应的字符
            char result = getChar(index);
            //追加到可变长字符串
            stringBuilder.append(result);
        }
        return stringBuilder.toString();
    }

    private static char getChar(int item) {
        //数字字符范围
        int digitalBound = 10;
        //字符范围
        int charBound = 26;
        Random random = new Random();
        int index;
        char c;
        //根据调用时候的三个选项,生成数字、大写字母、小写字母三种不同的字符
        if (item == 0) {
            index = random.nextInt(digitalBound);
            c = (char) ('0' + index);
        } else if (item == 1) {
            index = random.nextInt(charBound);
            c = (char) ('A' + index);
        } else {
            index = random.nextInt(charBound);
            c = (char) ('a' + index);
        }
        return c;
    }
}
import java.awt.*;
import java.awt.image.BufferedImage;

/**
 * @author mq_xu
 * @ClassName ImageUtil
 * @Description 验证码生成
 * @Date 2019/11/18
 * @Version 1.0
 **/
public class ImageUtil {
    public static BufferedImage getImage(int width, int height, String content) {
        //创建指定大小和图片模式的缓冲图片对象
        BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        //绘图对象
        Graphics2D graphics = (Graphics2D) img.getGraphics();
        //设置颜色
        graphics.setColor(new Color(68, 134, 49));
        //绘制填充矩形
        graphics.fillRect(0, 0, width, height);
        //设置画笔颜色
        graphics.setPaint(new Color(60, 63, 65));
        //设置字体
        Font font = new Font("微软雅黑", Font.BOLD, 40);
        graphics.setFont(font);
        //在指定位置绘制字符串
        graphics.drawString(content, width / 3, height / 2);
        return img;
    }
}
import com.scs.web.blog.util.ImageUtil;
import com.scs.web.blog.util.StringUtil;

import javax.imageio.ImageIO;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.OutputStream;

/**
 * @author mq_xu
 * @ClassName CodeController
 * @Description 验证码请求接口
 * @Date 2019/11/14
 * @Version 1.0
 **/
@WebServlet(urlPatterns = {"/api/code"})
public class CodeController extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //获取随机验证码
        String code = StringUtil.getRandomString();
        //存入session
        HttpSession session = req.getSession();
        session.setAttribute("code", code);
        //将sessionId通过响应头传回客户端
        resp.setHeader("Access-Token",session.getId());
         //调过生成验证码图片的方法
        BufferedImage img = ImageUtil.getImage(200, 100, code);
        //设置resp的响应内容类型,前端将是blob
        resp.setContentType("image/jpg");
        //将图片通过输出流返回给客户端
        OutputStream out = resp.getOutputStream();
        ImageIO.write(img, "jpg", out);
        out.close();
    }
}

        BufferedReader reader = req.getReader();
        StringBuilder stringBuilder = new StringBuilder();
        String line;
        while ((line = reader.readLine()) != null) {
            stringBuilder.append(line);
        }
        logger.info("登录用户信息:" + stringBuilder.toString());
        Gson gson = new GsonBuilder().create();
        UserDto userDto = gson.fromJson(stringBuilder.toString(), UserDto.class);
        //客户端输入的验证码
        String inputCode = userDto.getCode().trim();
        //取得客户端请求头里带来的token
        String sessionId = req.getHeader("Access-Token");
        //从自定义的监听代码中取得之前的session对象
        MySessionContext myc = MySessionContext.getInstance();
        HttpSession session = myc.getSession(sessionId);
        //取得当时存入的验证码
        String correctCode = session.getAttribute("code").toString();
        PrintWriter out = resp.getWriter();
        //忽略大小写比对
        if (inputCode.equalsIgnoreCase(correctCode)) {
            //验证码正确,进入登录业务逻辑调用
            Result result = userService.signIn(userDto);
        } else {
            //验证码错误,直接将错误信息返回给客户端,不要继续登录流程了
            Result result = Result.failure(ResultCode.USER_VERIFY_CODE_ERROR);
        }
        out.print(gson.toJson(result));
        out.close();
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * @author mq_xu
 * @ClassName CORSFilter
 * @Description 跨域过滤器类
 * @Date 2019/10/3
 * @Version 1.0
 **/
@WebFilter(urlPatterns = "/*")
public class CorsFilter implements Filter {
    private static Logger logger = LoggerFactory.getLogger(CorsFilter.class);

    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
        HttpServletResponse response = (HttpServletResponse) res;
        response.setHeader("Access-Control-Allow-Origin", "*");
        response.setHeader("Access-Control-Allow-Methods", "POST, GET, PUT, OPTIONS, DELETE");
        response.setHeader("Access-Control-Max-Age", "3600");
        //允许客户端请求头携带
        response.setHeader("Access-Control-Allow-Headers", "x-requested-with, Content-Type,Access-Token");
        //允许给客户端响应头携带
        response.setHeader("Access-Control-Expose-Headers", "Access-Token");
        response.setHeader("Access-Control-Allow-Credentials", "true");
        chain.doFilter(req, res);
    }

    @Override
    public void init(FilterConfig filterConfig) {
        logger.info("跨域过滤器初始化");
    }

    @Override
    public void destroy() {
        logger.info("跨域过滤器销毁");
    }

}
<template>
    <div id="bg">
        <router-link to="/">首页</router-link>
        <div class="login-box">
            <form class="login-form">
                <input type="text" v-model="userDto.mobile" id="mobile" />
                <input type="password" v-model="userDto.password" />
                <div class="code-box">
                    <input type="text" v-model="userDto.code" class="code" />
                    <img class="verify" @click.prevent="refresh" ref="codeImg" />
                </div>
                <input type="button" class="btn btn-lg dark-fill" value="登录" @click="signIn(userDto)" />
                <router-link to="/sign-up">没有账号?去注册</router-link>
            </form>
        </div>
    </div>
</template>
<script>
export default {
    data() {
        return {
            userDto: {
                mobile: '',
                password: '',
                code: ''
            },
            token: ''
        };
    },
    created() {
        this.axios.get(this.GLOBAL.baseUrl + '/code', { responseType: 'blob' }).then(res => {
            // console.log(res);
            var img = this.$refs.codeImg;
            let url = window.URL.createObjectURL(res.data);
            img.src = url;
            console.log(res.headers);
            //取得后台通过响应头返回的sessionId的值
            this.token = res.headers['access-token'];
            console.log(this.token);
        });
    },
    methods: {
        signIn(userDto) {
            this.axios({
                method: 'post',
                url: this.GLOBAL.baseUrl + '/user/sign-in',
                data: JSON.stringify(this.userDto),
                headers: {
                    'Access-Token': this.token  //将token放在请求头带到后端
                }
            }).then(res => {
                if (res.data.msg === '成功') {
                    alert('登录成功');
                    localStorage.setItem('user', JSON.stringify(res.data.data));
                    this.$router.push('/');
                } else {
                    alert(res.data.msg);
                    this.userDto.code = '';
                }
            });
        },
        refresh() {
            this.axios.get(this.GLOBAL.baseUrl + '/code', { responseType: 'blob' }).then(res => {
                console.log(res);
                var img = this.$refs.codeImg;
                let url = window.URL.createObjectURL(res.data);
                img.src = url;
            });
        }
    }
};
</script>
<style scoped>
</style>

可以看下后台的信息,两个id的值一致


后端

登录请求的请求头,可以看到带着的Access-Token


登录请求头
上一篇 下一篇

猜你喜欢

热点阅读