验证码生成 EasyCaptcha

11 篇文章 0 订阅
5 篇文章 0 订阅

验证码生成 EasyCaptcha

JavaWeb图形验证码,支持gif验证码,可用于基于的session的web项目和前后端分离的项目。

源码地址: https://gitee.com/jeesys/EasyCaptcha/

一、引入依赖

引入EasyCaptcha

<dependency>
    <groupId>com.github.whvcse</groupId>
	<artifactId>easy-captcha</artifactId>
	<version>1.6.2</version>
</dependency>

二、二维码常用类型

  • png类型
@Api("验证码图片获取")
@RestController
@RequestMapping(value = "/v1/captcha")
public class CaptchaController {
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @ResponseBody
    @GetMapping
    @ResponseResult
    @ApiOperation("验证码图片获取")
    public CaptchaVO captcha(HttpServletRequest request, HttpServletResponse response) throws Exception {
        SpecCaptcha specCaptcha = new SpecCaptcha(130, 48, 5);
        String verCode = specCaptcha.text().toLowerCase();
        String key = UUID.randomUUID().toString();
        // 存入redis并设置过期时间为30分钟
        redisTemplate.opsForValue().set(key, verCode, 30, TimeUnit.MINUTES);

        CaptchaVO captchaVO = new CaptchaVO();
        captchaVO.setKey(key);
        captchaVO.setImage(specCaptcha.toBase64());

        return captchaVO;
    }

三、创建Captcha注释

@Documented
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Captcha {

    /**
     * 唯一标识
     */
    String value() default "";
}

二、创建切面类

@Aspect
@Component
public class CaptchaAspect {

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    /**
     * 此处的切点是注解的方式,也可以用包名的方式达到相同的效果
     * '@Pointcut("execution(* com.wwj.springboot.service.impl.*.*(..))")'
     */
    @Pointcut("@annotation(com.wayz.lbi.cloud.annotation.Captcha)")
    public void captcha() {
    }

    /**
     * 环绕增强,相当于MethodInterceptor
     */
    @Around("captcha()")
    public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Captcha annotation = signature.getMethod().getAnnotation(Captcha.class);
        String codevalue = annotation.value();
        Object[] args = joinPoint.getArgs();
        Object arg = args[0];
        UserTO userTO = (UserTO) arg;
        if (userTO != null && userTO.getPhone() != null) {
            String phone = userTO.getPhone();
            String isSmsLogin = userTO.getCode();
            String frequencykey = codevalue + phone + ":frequency";
            String timekey = codevalue + phone + ":time";
            Integer integer = (Integer) redisTemplate.opsForValue().get(frequencykey);  //用户登录失败,integer不为null
            if (integer != null && integer >= 5) {
                Object timeValue = redisTemplate.opsForValue().get(timekey);
                throw new CloudException(CloudErrorCode.ACCOUNT_FREEZE, Collections.singletonMap(Global.ERROR_INFO,
                        String.format(CloudErrorCode.ACCOUNT_FREEZE.getMessage(), timeValue)));
            }
            // 密码当天24小时内填写失败次数大于3次,触发验证码机制
            if ((integer != null && integer >= 3)||codevalue.equals("put")||!StringUtils.isEmpty(isSmsLogin)) {
                String verKey = userTO.getVerKey();
                String verCode = userTO.getVerCode();
                if (StringUtils.isAnyEmpty(verKey, verCode)) {
                    throw new CloudException(CloudErrorCode.VERIFICATION_CODE_ERROR);
                }
                String redisCode = (String) redisTemplate.opsForValue().get(verKey);
                if (StringUtils.isAnyEmpty(redisCode)) {
                    throw new CloudException(CloudErrorCode.VERIFICATION_CODE_ERROR);
                }
                //仅使用一次,在校验前删除验证码
                redisTemplate.delete(verKey);
                // 判断验证码
                if (!StringUtils.equalsIgnoreCase(redisCode, verCode.trim())) {
                    throw new CloudException(CloudErrorCode.VERIFICATION_CODE_ERROR);
                }
            }
            try {
                return joinPoint.proceed();
            } catch (Throwable throwable) {
                needCaptcha(frequencykey, timekey);
                throw throwable;
            }
        }
        return joinPoint.proceed();
    }

    private void needCaptcha(String frequencykey, String timekey) {
        Integer increment = (Integer) redisTemplate.opsForValue().get(frequencykey);
        if (increment == null) {
            //默认密码错误记录两小时
            redisTemplate.opsForValue().set(frequencykey, 1, 24, TimeUnit.HOURS);
        } else {
            Long increment1 = redisTemplate.opsForValue().increment(frequencykey);
            if (increment1 != null && increment1 == 5L) {
                String format = LocalDateTime.now()
                        .plusHours(2).format(DateTimeFormatter.ofPattern("HH:mm"));
                //超过五次则锁定两小时
                redisTemplate.expire(frequencykey, 2, TimeUnit.HOURS);
                redisTemplate.opsForValue().set(timekey, format);
            }
        }
    }
}

用于用户登录失败的时候进行记录

四、创建验证码类

@Api("验证码图片获取")
@RestController
@RequestMapping(value = "/v1/captcha")
public class CaptchaController {
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @ResponseBody
    @GetMapping
    @ResponseResult
    @ApiOperation("验证码图片获取")
    public CaptchaVO captcha(HttpServletRequest request, HttpServletResponse response) throws Exception {
        SpecCaptcha specCaptcha = new SpecCaptcha(130, 48, 5);
        String verCode = specCaptcha.text().toLowerCase();
        String key = UUID.randomUUID().toString();
        // 存入redis并设置过期时间为30分钟
        redisTemplate.opsForValue().set(key, verCode, 30, TimeUnit.MINUTES);

        CaptchaVO captchaVO = new CaptchaVO();
        captchaVO.setKey(key);
        captchaVO.setImage(specCaptcha.toBase64());

        return captchaVO;
    }

    @ApiOperation(value = "根据phone查询错误次数",
            notes = "codevalue 表示不同的场景   登录+验证码校验为one ,  注册为post  ,重置密码为put;")
    @ResponseResult
    @GetMapping("/time")
    public int getCaptchaTime(@RequestParam String phone, @RequestParam String codevalue) {

        String frequencykey = codevalue + phone + ":frequency";
        Integer integer = (Integer) redisTemplate.opsForValue().get(frequencykey);
        return integer==null?0:integer;
    }
}

和用户登录类

 @Captcha("one")
    @ApiOperation("登录+验证码校验")
    @PostMapping(value = "/one")
    public UserVO getByCodeOrPass(@RequestBody UserTO userTO) {
        checkGetParam(userTO);
        return userService.getByCodeOrPass(userTO);
    }

    @PostMapping
    public boolean post(@RequestBody @Valid UserTO userTO) {
        return userService.post(userTO);
    }

    @Captcha("put")
    @PutMapping
    public boolean put(@RequestBody UserTO userTO) {
        checkPut(userTO);
        return userService.put(userTO);
    }

用户登录时先请求/time,再登录请求/one

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值