实现了标准的图形验证码、滑动验证码、点击验证码等多种验证码类型。

仓库坐标

Maven

<dependency>
    <groupId>com.luamas.thinkbridge</groupId>
    <artifactId>captcha-spring-boot-starter</artifactId>
</dependency>

Gradle

implementation("com.luamas.thinkbridge:captcha-spring-boot-starter")

获取验证码接口规范

请求示例

请求参数

字段

说明

类型

是否必填

默认值

备注

type

验证码类型

string

是

key

验证码key

string

否

空

clientId

客户端id

string

否

空

JSON

{
    "type":"blockPuzzle",
    "clientId":"slider-6a8fa08c-fe2e-4ea2-8822-001063d94e1e"
}

Java 类属性

/
 * 验证码类型
 /
private String type;
/
 * 验证码key
 */
private String key;
/*
 * 客户端id
 */
private String clientId;

响应示例

响应参数

字段

说明

类型

备注

success

是否成功

boolean

data

响应的标准体

obj

-data

图片类型泛型,type不一致,内容字段也不一致

obj

--base64

base64编码的图片

string

--width

图片宽度

number

--height

图片高度

number

-expire

过期时间,单位秒

number

-key

验证码key,如果请求传入,则和请求的值相同

string

-clientId

客户端id,和请求的值一致

string

error

错误信息对象,只有success为false时才会有

obj

-message

错误信息

string

-code

错误码

number

JSON

{
    "success": true,
    "data": {
        "data": {
            "base64": "data:image/png;base64,xxx",
            "width": 310,
            "height": 155,
            "blockPuzzleBase64": "data:image/png;base64,xxx"
        },
        "expire": 900,
        "type": "blockPuzzle",
        "key": "987c604908144bc192149a36360c27b4",
        "clientId": "slider-6a8fa08c-fe2e-4ea2-8822-001063d94e1e"
    }
}

Java 类属性

private M data;
/
 * 验证码过期时间
 */
private Duration expire;
/
 * 验证码类型
 */
private String type;
/
 * 验证码key
 */
private String key;
/
 * 客户端id
 */
private String clientId;

各个验证码的响应参数

  1. character 类型 使用标准模版即可

  2. blockPuzzle 类型(特殊字段)

字段

说明

类型

备注

blockPuzzleBase64

滑动验证码的base64编码

string

/**
 * 拼图验证码base64
 */
private String blockPuzzleBase64;
  1. clickWord 类型(特殊字段)

字段

说明

类型

备注

words

点击验证码的文字

array

private List<String> words;

校验验证码接口规范

请求示例

请求参数

字段

说明

类型

是否必填

默认值

备注

type

验证码类型

string

是

data

按照类型不同,内容不同

obj

是

空

key

验证码key

string

否

空

clientId

客户端id

string

否

空

JSON

{
    "type":"blockPuzzle",
    "data":
    {
        "point":
        {
            "x":164.3,
            "y":5
        }
    },
    "key":"987c604908144bc192149a36360c27b4",
    "clientId":"slider-6a8fa08c-fe2e-4ea2-8822-001063d94e1e"
}

Java 类属性(仅比 CaptchaDto 多一个 data 字段)

/
 * 验证码类型
 */
private String type;
/
 * 验证码key
 */
private String key;
/
 * 客户端id
 */
private String clientId;
/
 * 数据对象
 * @return 数据对象
 */
private M data;

各个验证码的请求参数

  1. character 类型(特殊字段)

字段

说明

类型

备注

value

字符验证码的值

string

/**
 * 字符验证码的值
 */
private String value;
  1. blockPuzzle 类型(特殊字段)

字段

说明

类型

备注

blockPuzzleBase64

滑动验证码的base64编码

string

/**
 * 拼图验证码坐标
 */
private Point point;
  1. clickWord 类型(特殊字段)

字段

说明

类型

备注

words

点击验证码的文字

array

/**
 * 点击验证码坐标
 */
private List<Point> points;

响应示例

响应参数

字段

说明

类型

备注

success

是否成功

boolean

data

响应的标准体

obj

error

错误信息对象,只有success为false时才会有

obj

-message

错误信息

string

-code

错误码

number

JSON

{
    "success": false,
    "data": null,
    "error": {
        "message": "已失效,请重新获取",
        "code": 3101
    }
}

错误代码

字段

说明

备注

3101

已失效,请重新获取

3102

验证失败

3103

获取验证码失败,请联系管理员

3104

底图未初始化成功,请检查路径

3105

get接口请求次数超限,请稍后再试!

3106

无效请求,请重新获取验证码

3107

接口验证失败数过多,请稍后再试

3108

check接口请求次数超限,请稍后再试!

3109

验证请求次数超限!

public static final CaptchaResultCode CAPTCHA_INVALID = new CaptchaResultCode(3101, "captcha.CAPTCHA_INVALID", "{0}已失效,请重新获取");
public static final CaptchaResultCode CAPTCHA_COORDINATE_ERROR = new CaptchaResultCode(3102, "captcha.CAPTCHA_COORDINATE_ERROR", "{0}验证失败");
public static final CaptchaResultCode CAPTCHA_ERROR = new CaptchaResultCode(3103, "captcha.CAPTCHA_ERROR", "{0}获取验证码失败,请联系管理员");
public static final CaptchaResultCode CAPTCHA_BASEMAP_NULL = new CaptchaResultCode(3104, "captcha.CAPTCHA_BASEMAP_NULL", "{0}底图未初始化成功,请检查路径");
public static final CaptchaResultCode REQ_LIMIT_GET_ERROR = new CaptchaResultCode(3105, "captcha.REQ_LIMIT_GET_ERROR", "{0}get接口请求次数超限,请稍后再试!");
public static final CaptchaResultCode REQ_INVALID = new CaptchaResultCode(3106, "captcha.REQ_INVALID", "{0}无效请求,请重新获取验证码");
public static final CaptchaResultCode REQ_LOCK_GET_ERROR = new CaptchaResultCode(3107, "captcha.REQ_LOCK_GET_ERROR", "{0}接口验证失败数过多,请稍后再试");
public static final CaptchaResultCode REQ_LIMIT_CHECK_ERROR = new CaptchaResultCode(3108, "captcha.REQ_LIMIT_CHECK_ERROR", "{0}check接口请求次数超限,请稍后再试!");
public static final CaptchaResultCode REQ_LIMIT_VERIFY_ERROR = new CaptchaResultCode(3109, "captcha.REQ_LIMIT_VERIFY_ERROR", "{0}验证请求次数超限!");

示例代码

package com.luamas.thinkbridge.integration.demo.captcha.controller;

import com.luamas.thinkbridge.common.base.vo.ResponseVo;
import com.luamas.thinkbridge.common.captcha.common.CaptchaManger;
import com.luamas.thinkbridge.common.captcha.common.dto.CaptchaDto;
import com.luamas.thinkbridge.common.captcha.common.dto.CaptchaVerificationDto;
import com.luamas.thinkbridge.common.captcha.common.vo.CaptchaVo;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;

@RequiredArgsConstructor
@RestController
@RequestMapping("api/captcha")
@Tag(name = "验证码")
public class CaptchaController {
    private final CaptchaManger captchaManger;

    @Operation(summary = "获取验证码",
            description = "生成滑块/点选等验证码,返回背景图、滑块图、UUID等信息")
    @PostMapping("/get")
    public ResponseVo<CaptchaVo> getCaptcha(@RequestBody CaptchaDto dto) {
        CaptchaVo captchaVO = captchaManger.generate(dto);
        return ResponseVo.success(captchaVO);
    }

    @Operation(summary = "校验验证码(check)",
            description = "用户点选/滑动后提交,进行第一次校验")
    @PostMapping("/check")
    public ResponseVo<Boolean> check(@RequestBody CaptchaVerificationDto<?, ?> dto) {
        captchaManger.check(dto);
        return ResponseVo.success();
    }

    @Operation(summary = "最终校验验证码(verify)",
            description = "表单真正提交时进行最终二次校验,确保安全")
    @PostMapping("/verify")
    public ResponseVo<Boolean> verify(@RequestBody CaptchaVerificationDto<?, ?> dto) {
        captchaManger.verify(dto);
        return ResponseVo.success();
    }
}