Springboot集成Kaptcha实现前后端分离的验证码功能

https://blog.csdn.net/m0_38121868/article/details/83416484

1、简介kaptcha

    Kaptcha是一个基于SimpleCaptcha的验证码开源项目。

2、实现原理

    首先,使用Kaptcha生成一个验证码captcha;

    然后,为这个验证码生成一个token,以token为key,captcha为value存在redis中,然后将该token和生成的验证图片传给前端;

    最后,在用户登录的时候,前端将这个token,以及用户所输入的验证码传到后台,后台根据token到redis中取值,对比用户所输入的验证码和redis中读取到的验证码是否一致,如果一致,验证通过,不一致,验证失败。

3、示例 

    1)引入kaptcha依赖(百度搜索 maven kaptcha)

    

<!--Kaptcha是一个基于SimpleCaptcha的验证码开源项目-->
        <dependency>
            <groupId>com.github.penggle</groupId>
            <artifactId>kaptcha</artifactId>
            <version>2.3.2</version>
        </dependency>
    2)写一个Kaptcha配置类(网上也有很多使用xml配置文件,可以自行搜索)

 
 
import com.google.code.kaptcha.impl.DefaultKaptcha;
import com.google.code.kaptcha.util.Config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
 
import java.util.Properties;
 
/**
 * @author sjm
 * @date 2018-10-26
 * 生成验证码的配置
 */
@Configuration
public class KaptchaConfig {
    @Bean
    public DefaultKaptcha producer(){
        Properties properties = new Properties();
        properties.put("kaptcha.border", "no");
        properties.put("kaptcha.textproducer.font.color", "black");
        properties.put("kaptcha.textproducer.char.space", "10");
        properties.put("kaptcha.textproducer.char.length","4");
        properties.put("kaptcha.image.height","34");
        properties.put("kaptcha.textproducer.font.size","25");
 
        properties.put("kaptcha.noise.impl","com.google.code.kaptcha.impl.NoNoise");
        Config config = new Config(properties);
        DefaultKaptcha defaultKaptcha = new DefaultKaptcha();
        defaultKaptcha.setConfig(config);
        return defaultKaptcha;
    }
}
     3)创建一个实体类(目前没有用到,如果是不存在redis中,选择存在数据库里面就需要)

 
 
import lombok.Data;
 
@Data
public class Captcha {
    private String token;
    private String captcha;
}
  4)CaptchaService

import com.geepush.openapi.common.constant.RedisKeys;
import com.geepush.openapiclient.utils.StringRedisUtil;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Service;
 
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
 
@Service
public class CaptchaService {
    @Value("${server.session.timeout}")
    private Integer timeout;
 
    public Map<String,Object> createToken(String captcha){
        //生成一个token
        String cToken = UUID.randomUUID().toString();
 
        //生成验证码对应的token  以token为key  验证码为value存在redis中
        StringRedisTemplate template = StringRedisUtil.getStringRedisTemplate();
        ValueOperations<String, String> valueOperations = template.opsForValue();
        String key = String.format(RedisKeys.CLIENT_TOKEN, cToken);
        valueOperations.set(key, captcha);
        template.expire(key, timeout, TimeUnit.MINUTES);
 
        Map<String, Object> map = new HashMap<>();
        map.put("cToken", cToken);
        map.put("expire", timeout);
        return map;
    }
}
     4)controller中

   @Autowired
   private DefaultKaptcha producer;
 
   @Autowired
   private CaptchaService captchaService;
      a 获取验证码接口

/**
     * 获取验证码
     * @param response
     * @return
     * @throws ServletException
     * @throws IOException
     */
    @ResponseBody
    @POStMapping("/captcha")
    public Map<String, Object> captcha(HttpServletResponse response) throws ServletException, IOException {
 
        // 生成文字验证码
        String text = producer.createText();
        // 生成图片验证码
        ByteArrayOutputStream outputStream = null;
        BufferedImage image = producer.createImage(text);
 
        outputStream = new ByteArrayOutputStream();
        ImageIO.write(image, "jpg", outputStream);
 
        // 对字节数组Base64编码
        BASE64Encoder encoder = new BASE64Encoder();
 
        // 生成captcha的token
        Map<String, Object> map =captchaService.createToken(text);
        map.put("img", encoder.encode(outputStream.toByteArray()));
        return map;
    }
   b 登录接口  (验证验证码)

/**
     * 登录返回令牌
     * @param username
     * @param password
     * @param cToken 验证码对应的ctoken
     * @param captcha 用户输入的验证码
     * @return
     */
    @PostMapping("/login")
    public ResponseBean login(@RequestParam("username") String username,
                              @RequestParam("password") String password,
                              @RequestParam("cToken") String cToken,
                              @RequestParam("captcha") String captcha) {
        User userBean = userService.find(username);
        if (userBean == null) {
//            throw new UnauthorizedException("用户不存在");
            return new ResponseBean(1, "用户不存在");
        } else {
            //根据传过来的ctoken验证验证码
            StringRedisTemplate redisTemplate = StringRedisUtil.getStringRedisTemplate();
            ValueOperations operations = redisTemplate.opsForValue();
            String cKey = String.format(RedisKeys.CLIENT_TOKEN, cToken);
           //判断验证码是否还存在
            if(redisTemplate.hasKey(cKey)){
                if(operations.get(cKey).equals(captcha)){
                    //验证通过之后删除对应的key
                    redisTemplate.delete(cKey);
                    if (userBean.getPassword().equals(password)) {
                        String token = JWTUtil.sign(username, password);
                        //登陆成功后将token存于redis
                        StringRedisTemplate template = StringRedisUtil.getStringRedisTemplate();
                        ValueOperations<String, String> valueOperations = template.opsForValue();
                        String key = String.format(RedisKeys.CLIENT_TOKEN, username);
                        valueOperations.set(key, token);
                        template.expire(key, timeout, TimeUnit.MINUTES);
                        return new ResponseBean(0, "Login success", token);
                    } else {
//                throw new UnauthorizedException("密码错误");
                        return new ResponseBean(1, "密码错误");
                    }
                }else {
                    return new ResponseBean(1, "验证码错误");
                }
            }else {
                return new ResponseBean(1, "验证码不存在");
            }
        }
    }
 
--------------------- 
作者:苏一念 
来源:CSDN 
原文:https://blog.csdn.net/m0_38121868/article/details/83416484 
版权声明:本文为博主原创文章,转载请附上博文链接!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值