View on GitHub

captcha

CAPTCHA 是一个基于 Spring Boot 框架的验证码框架,它通过 AOP 的方式完成包含验证码生成、发送、存储等验证码相关业务,以避免与业务代码耦合。目前提供邮箱验证码、短信验证码、图像验证码、谷歌 reCAPTCHA。

aliyun-sms

Sonatype Nexus (Snapshots) Sonatype Nexus (Snapshots)

简介

aliyun-smsCAPTCHA 项目的一个拓展,提供短信验证码发送功能(基于 阿里云短信服务 )。 使用此拓展需要提供阿里云短信服务的 密钥模板ID签名 , 若您仍未拥有密钥请前往创建。

完整示例

此示例同时包含图像验证码与短信验证码示例,在开始之前请先创建一个 Spring Boot 的 Web 项目,并 添加依赖

添加依赖

在 Maven 项目的 pom.xml 文件中添加依赖:

<dependency>
    <groupId>cn.dustlight.captcha</groupId>
    <artifactId>aliyun-sms</artifactId>
    <version>1.0.1</version>
</dependency>

配置文件

application.yaml:

dustlight:
  captcha:
    generator:
      random-string:
        chars: "0123456789" # 随机字符池
        length: 4 # 随机字符验证码长度
    sender:
      alibaba:
        sms:
          access-key-id: <ACCESS_KEY_ID> # 阿里云密钥 ID
          access-key-secret: <ACCESS_KEY_SECRET> # 阿里云密钥 Key
          default-template-code: <TEMPLATE_CODE> # 默认短信模板 Code
          default-sign-name: <SIGN_NAME> # 默认短信签名

启用 CAPTCHA

添加注解 “@EnableCaptcha” :

package com.example.demo;

import cn.dustlight.captcha.annotations.*;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
@EnableCaptcha // 开启 CAPTCHA
public class DemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }

}

创建 Controller

创建 “TestController.java” :

package com.example.demo;

import cn.dustlight.captcha.annotations.*;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.web.bind.annotation.*;

@RestController
@RestControllerAdvice
public class TestController {

    Log log = LogFactory.getLog(TestController.class.getName());

    /**
     * 获取图片验证码
     *
     * @param code 生成的验证码
     */
    @RequestMapping("/captcha/image")
    @SendCode
    public void image(@CodeValue String code) {
        log.info(String.format("图片验证码:%s", code));
    }

    /**
     * 获取短信验证码(注解 "@VerifyCode" 表示在此之前先验证图片验证码,注解 "@SendCode" 中的 sender 指定为 "aliyunSmsSender" 表示使用阿里云短信服务)
     *
     * @param code    被验证的图片验证码
     * @param smsCode 生成的短信验证码,注解 '@CodeValue("sms")' 表示短信验证码的名称为 "sms" ,用于区别先前的图片验证码。
     * @param phone   目标手机,注解 "@CodeParam" 表示此值将被存储
     */
    @RequestMapping("/captcha/sms")
    @VerifyCode
    @SendCode(value = "sms", sender = @Sender("aliyunSmsSender"))
    public void sms(@CodeValue String code,
                    @CodeValue("sms") String smsCode,
                    @CodeParam("sms") String phone) {
        log.info(String.format("短信验证码:%s,目标手机:%s", smsCode, phone));
    }

    /**
     * 验证短信验证码
     *
     * @param code  短信验证码
     * @param phone 手机号码,从验证码存储器取出的值。
     * @return
     */
    @RequestMapping("/verify")
    @VerifyCode("sms")
    public String verify(@CodeValue("sms") String code, @CodeParam("sms") String phone) {
        log.info(String.format("%s 验证成功,手机号码:%s", code, phone));
        return phone;
    }

    @ExceptionHandler(Exception.class)
    @ResponseStatus
    public String onException(Exception e) {
        return e.getMessage();
    }
}

创建前端页面

在 “resources/static” 目录下创建文件 “index.html” :

<!DOCTYPE html>
<html lang="zh">
<head>
    <title>Aliyun SMS 测试</title>
    <meta charset="utf-8"/>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<header style="padding: 8px;">
    <h1><a href="/">Aliyun SMS 测试</a></h1>
</header>
<main style="padding: 16px;">
    <div>
        <h3>1. 发送手机验证码</h3>
        <form>
            <div>
                <label>手机号码:+86</label>
                <input id="phone" type="text" placeholder="请输入您的手机号码">
            </div>
            <div>
                <label>验证码:</label>
                <input id="code" type="text" placeholder="请输入图片中的数字">
                <img id="image" width="100px" height="50px">
            </div>
            <div style="margin: 8px;">
                <input id="sendSms" type="submit" value="发送短信验证码">
            </div>
        </form>
    </div>
    <div style="margin-top: 16px;">
        <h3>2. 验证</h3>
        <form>
            <div>
                <label>短信验证码:</label>
                <input id="sms" type="text" placeholder="请输入您收到的短信验证码">
            </div>
            <div style="margin: 8px;">
                <input id="verify" type="submit" value="验证">
            </div>
        </form>
    </div>
</main>
<script>
    const submitBtn = document.getElementById("sendSms")
    const image = document.getElementById("image")
    const phone = document.getElementById("phone")
    const code = document.getElementById("code")

    const sms = document.getElementById("sms")
    const verifyBtn = document.getElementById("verify")

    function post(url, data) {
        let dataString = "";
        for (let key in data) {
            if (dataString.length > 0) dataString += "&";
            dataString += encodeURIComponent(key) + "=" + encodeURIComponent(data[key])
        }
        return fetch(url, {
            method: "post",
            headers: {'Content-Type': 'application/x-www-form-urlencoded'},
            body: dataString
        }).then(response => {
            if (response.ok) return response.text(); else return response.text().then(str => {
                throw new Error(str)
            })
        })
    }

    function loadImage() {
        image.setAttribute("src", "/captcha/image?" + new Date().getTime())
    }

    function sendSms(e) {
        e.preventDefault()
        post("/captcha/sms", {code: code.value, phone: "+86" + phone.value})
            .then(response => {
                alert("发送成功!" + response)
                loadImage()
            })
            .catch(e => {
                alert("错误:" + e.message)
                loadImage()
            })
    }

    function verify(e) {
        e.preventDefault()
        post("/verify", {code: sms.value})
            .then(phone => alert("手机:" + phone + ", 验证成功!"))
            .catch(e => alert("错误:" + e.message))
    }

    submitBtn.onclick = sendSms
    verifyBtn.onclick = verify
    image.onclick = loadImage

    loadImage()
</script>
</body>
</html>

运行

运行您的项目,打开 http://localhost:8080/ 进行测试。

获取帮助

如果需要报告问题或者功能需求,请在Github中 创建issue 。若有其他问题或建议,请发送电子邮件至 hansin@dustlight.cn