SpringBoot + Apache Shrio + JWT + Reids 添加验证码功能

我们在上篇文章中:SpringBoot + Apache Shrio + JWT +Redis 实现权限认证,讲述如何基于用户名和密码实现权限认证功能,我们在此基础上进行功能完善,在用户登入时除了输入用户名和密码,还需要添加验证码字段进行验证。下面开始梳理验证码功能点

kaptcha简介

Kaptcha 是一个可高度配置的实用验证码生成工具,可自由配置的选项如:

  • 验证码的字体
  • 验证码字体的大小
  • 验证码字体的字体颜色
  • 验证码内容的范围(数字,字母,中文汉字!)
  • 验证码图片的大小,边框,边框粗细,边框颜色
  • 验证码的干扰线
  • 验证码的样式(鱼眼样式、3D、普通模糊、...)

Kaptcha 配置参数表

Constant描述默认值
kaptcha.border图片边框,合法值:yes , noyes
kaptcha.border.color边框颜色,合法值: r,g,b (and optional alpha) 或者 white,black,blue.black
kaptcha.image.width图片宽200
kaptcha.image.height图片高50
kaptcha.producer.impl图片实现类com.google.code.kaptcha.impl.DefaultKaptcha
kaptcha.textproducer.impl文本实现类com.google.code.kaptcha.text.impl.DefaultTextCreator
kaptcha.textproducer.char.string文本集合,验证码值从此集合中获取abcde2345678gfynmnpwx
kaptcha.textproducer.char.length验证码长度5
kaptcha.textproducer.font.names字体Arial, Courier
kaptcha.textproducer.font.size字体大小40px.
kaptcha.textproducer.font.color字体颜色,合法值: r,g,b 或者 white,black,blue.black
kaptcha.textproducer.char.space文字间隔2
kaptcha.noise.impl干扰实现类com.google.code.kaptcha.impl.DefaultNoise
kaptcha.noise.color干扰 颜色,合法值: r,g,b 或者 white,black,blue.black
kaptcha.obscurificator.impl图片样式:<br />水纹 com.google.code.kaptcha.impl.WaterRipple <br /> 鱼眼 com.google.code.kaptcha.impl.FishEyeGimpy <br /> 阴影 com.google.code.kaptcha.impl.ShadowGimpycom.google.code.kaptcha.impl.WaterRipple
kaptcha.background.impl背景实现类com.google.code.kaptcha.impl.DefaultBackground
kaptcha.background.clear.from背景颜色渐变,开始颜色light grey
kaptcha.background.clear.to背景颜色渐变, 结束颜色white
kaptcha.word.impl    文字渲染器com.google.code.kaptcha.text.impl.DefaultWordRenderer
kaptcha.session.keysession keyKAPTCHA_SESSION_KEY
kaptcha.session.datesession dateKAPTCHA_SESSION_DATE

SpringBoot 整合Kaptcha

在项目中引入kaptcha非常简单,我们只需要在pom.xml文件中引入 kaptcha就可以了

 <!-- 依赖kaptcha图形生成器  -->
		<dependency>
			<groupId>com.github.penggle</groupId>
			<artifactId>kaptcha</artifactId>
			<version>2.3.2</version>
		</dependency>

自定义kaptcha 工具类:

package com.zzg.util;

import java.util.Properties;

import com.google.code.kaptcha.impl.DefaultKaptcha;
import com.google.code.kaptcha.util.Config;

public class KaptchaUtil {
	private static KaptchaUtil instance;
	 
	private KaptchaUtil() {
	};
 
	public static KaptchaUtil getInstance() {
		if (instance == null) {
			instance = new KaptchaUtil();
		}
		return instance;
	}
 
	/**
	 * 生成DefaultKaptcha 默认配置
	 * @return
	 */
	public DefaultKaptcha produce() {
		Properties properties = new Properties();
		properties.put("kaptcha.border", "no");
		properties.put("kaptcha.border.color", "105,179,90");
		properties.put("kaptcha.textproducer.font.color", "blue");
		properties.put("kaptcha.image.width", "100");
		properties.put("kaptcha.image.height", "50");
		properties.put("kaptcha.textproducer.font.size", "27");
		properties.put("kaptcha.session.key", "code");
		properties.put("kaptcha.textproducer.char.length", "4");
		properties.put("kaptcha.textproducer.font.names", "宋体,楷体,微软雅黑");
		properties.put("kaptcha.textproducer.char.string", "0123456789ABCEFGHIJKLMNOPQRSTUVWXYZ");
		properties.put("kaptcha.obscurificator.impl", "com.google.code.kaptcha.impl.WaterRipple");
		properties.put("kaptcha.noise.color", "black");
		properties.put("kaptcha.noise.impl", "com.google.code.kaptcha.impl.DefaultNoise");
		properties.put("kaptcha.background.clear.from", "185,56,213");
		properties.put("kaptcha.background.clear.to", "white");
		properties.put("kaptcha.textproducer.char.space", "3");
		
		Config config = new Config(properties);
		DefaultKaptcha defaultKaptcha = new DefaultKaptcha();
		defaultKaptcha.setConfig(config);
		return defaultKaptcha;
	}

}

SpringBoot 添加验证码Controller

package com.zzg.controller;

import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import javax.imageio.ImageIO;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import com.google.code.kaptcha.impl.DefaultKaptcha;
import com.zzg.redis.RedisUtils;
import com.zzg.util.KaptchaUtil;

@RestController
public class KaptchaController {
	public static final String VRIFY_CODE = "VRIFYCODE";
	
	@GetMapping("/sys/kaptcha")
	public void defaultKaptcha(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse)
			throws Exception {
		
		byte[] captchaChallengeAsJpeg = null;
		ByteArrayOutputStream jpegOutputStream = new ByteArrayOutputStream();
		try {
			// 代码方式创建:DefaultKaptcha
			KaptchaUtil single = KaptchaUtil.getInstance();
			DefaultKaptcha defaultKaptcha = single.produce();
			// 生产验证码字符串并保存到session中
			String createText = defaultKaptcha.createText();
			// 基于session 方式
			//httpServletRequest.getSession().setAttribute(VRIFY_CODE, createText);
			// 基于redis 方式
			RedisUtils.hPut(VRIFY_CODE, createText, createText);
			// 使用生产的验证码字符串返回一个BufferedImage对象并转为byte写入到byte数组中
			BufferedImage challenge = defaultKaptcha.createImage(createText);
			ImageIO.write(challenge, "jpg", jpegOutputStream);
		} catch (IllegalArgumentException e) {
			httpServletResponse.sendError(HttpServletResponse.SC_NOT_FOUND);
			return;
		}
 
		// 定义response输出类型为image/jpeg类型,使用response输出流输出图片的byte数组
		captchaChallengeAsJpeg = jpegOutputStream.toByteArray();
		httpServletResponse.setHeader("Cache-Control", "no-store");
		httpServletResponse.setHeader("Pragma", "no-cache");
		httpServletResponse.setDateHeader("Expires", 0);
		httpServletResponse.setContentType("image/jpeg");
		ServletOutputStream responseOutputStream = httpServletResponse.getOutputStream();
		responseOutputStream.write(captchaChallengeAsJpeg);
		responseOutputStream.flush();
		responseOutputStream.close();
	}

}

注意:存储验证码的方式是采用redis 方式存储,是基于前后端分离模式决定。一般采取的模式是session 方式存储

ShiroConfig 配置对象开发验证码权限

在shiroConfig中对 获取验证码的数据接口开放权限

登入方法添加验证码验证

在LoginController.login(@RequestParam("username")String username, @RequestParam("password")String password, @RequestParam("captcha")String captcha) 中添加验证码请求参数

/**
     * 登录
     */
    @PostMapping("/sys/login")
    @ResponseBody
    public Map<String, Object> login(@RequestParam("username")String username, @RequestParam("password")String password, @RequestParam("captcha")String captcha) {
        Map<String, Object> result = new HashMap<>();
        
        //校验验证码
        //基于session的验证码
        // String sessionCaptcha = (String) SecurityUtils.getSubject().getSession().getAttribute(VRIFY_CODE);
        //基于redis的验证码
        String redisCaptcha = (String) RedisUtils.hGet(VRIFY_CODE, captcha);
        if (StringUtils.isEmpty(redisCaptcha)) {
        	 result.put("status", 400);
             result.put("msg", "验证码有误");
             return result;
        }

        //用户信息
        User user = userRepository.findByUsername(username);
        //账号不存在、密码错误
        if (user == null || !user.getPassword().equals(password)) {
            result.put("status", 400);
            result.put("msg", "账号或密码有误");
        } else {
            //生成token,并保存到redis
        	String token = JWTUtil.createToken(username);
        	RedisUtils.set(username,token);
        	RedisUtils.expire(username, EXPIRE_TIME);
        	// user->token 关系保存到mysql 中
        	TokenRelation relation = tokenRelationRepository.findByUsername(username);
        	if(relation == null){
        		relation = new TokenRelation();
        		relation.setUsername(username);
            	relation.setToken(token);
        	} else {
        		relation.setToken(token);
        	}
        	tokenRelationRepository.save(relation);
        	
        	result.put("token", token);
            result.put("status", 200);
            result.put("msg", "登陆成功");
            
            // 移除验证码
            RedisUtils.hDelete(VRIFY_CODE, captcha);
        }
        return result;
    }
    

效果演示:

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值