View on GitHub

captcha

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

email-sender

Sonatype Nexus (Snapshots) Sonatype Nexus (Snapshots)

简介

email-senderCAPTCHA 项目的一个拓展,提供邮箱验证码发送功能。基于 JavaMailSender 实现邮件发送功能,模板引擎为 FreeMaker 。

快速入门

添加依赖

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

<dependency>
    <groupId>cn.dustlight.captcha</groupId>
    <artifactId>email-sender</artifactId>
    <version>1.0.1</version>
</dependency>

启用 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);
    }

}

配置邮件服务器

在 application.yaml 添加邮件服务器配置:

spring:
  mail:
    host: <SMTP_HOST> # SMTP邮件发送服务器,例如:smtp.exmail.qq.com
    username: <SMTP_USERNAME> # SMTP 用户名
    password: <SMTP_PASSWORD> # SMTP 密码

创建邮件模板

在 resources 目录创建文件 sendCode.html :

<html>
<body>
您的验证码为: ${code}
</body>
</html>

创建 Controller

创建 EmailController.java :

package com.example.demo;

import cn.dustlight.captcha.annotations.*;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.logging.Logger;

@RestController
public class EmailController {

    /**
     * 发送邮箱验证码
     * <p>
     * 注解 '@Parameter' 为邮件发送器提供 邮件主题 以及 模板名。
     *
     * @param code  生产的验证码(此参数由验证码生成器传入并自动储存)
     * @param email 目标邮箱(此参数为 @RequestParam ,注解 @CodeParam 表示此参数将与验证码一起储存,以便验证成功后取出)
     */
    @RequestMapping("/email")
    @SendCode(sender = @Sender("emailCodeSender"),
            parameters = {
                    @Parameter(name = "SUBJECT", value = "邮箱验证"),
                    @Parameter(name = "TEMPLATE", value = "sendCode.html")
            })
    public String sendEmailCode(@CodeValue String code, @CodeParam String email) {
        Logger.getGlobal().info(code);
        return "send code success";
    }

    /**
     * 进行验证
     *
     * @param code  被验证的验证码(此参数为 @RequestParam)
     * @param email 验证成功后,传入储存的 email 参数。
     * @return
     */
    @RequestMapping("/verify")
    @VerifyCode
    public String verify(@CodeValue String code, @CodeParam String email) {
        Logger.getGlobal().info(email);
        return String.format("verify email '%s' success", email);
    }
}

运行

运行您的项目,打开 http://localhost:8080/email?email=xx@xx.com 进行测试。(将 xx@xx.com 改为您的电子邮箱) 收到验证码后,打开 http://localhost:8080/verify?code=xx 进行验证。(将 xx 改为您收到的验证码)

获取帮助

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

常见问题

验证码参数获取失败

发送邮件时,模板引擎无法找到参数:

----
FTL stack trace ("~" means nesting-related):
        - Failed at: ${code}  [in template "mail/EmailCode.html" at line 8, column 12]
----
        at freemarker.core.InvalidReferenceException.getInstance(InvalidReferenceException.java:134) ~[freemarker-2.3.30.jar!/:2.3.30]
        at freemarker.core.EvalUtil.coerceModelToTextualCommon(EvalUtil.java:481) ~[freemarker-2.3.30.jar!/:2.3.30]
        at freemarker.core.EvalUtil.coerceModelToStringOrMarkup(EvalUtil.java:401) ~[freemarker-2.3.30.jar!/:2.3.30]
        at freemarker.core.EvalUtil.coerceModelToStringOrMarkup(EvalUtil.java:370) ~[freemarker-2.3.30.jar!/:2.3.30]
        at freemarker.core.DollarVariable.calculateInterpolatedStringOrMarkup(DollarVariable.java:100) ~[freemarker-2.3.30.jar!/:2.3.30]
        at freemarker.core.DollarVariable.accept(DollarVariable.java:63) ~[freemarker-2.3.30.jar!/:2.3.30]
        at freemarker.core.Environment.visit(Environment.java:334) ~[freemarker-2.3.30.jar!/:2.3.30]
        at freemarker.core.Environment.visit(Environment.java:340) ~[freemarker-2.3.30.jar!/:2.3.30]
        at freemarker.core.Environment.process(Environment.java:313) ~[freemarker-2.3.30.jar!/:2.3.30]
        at freemarker.template.Template.process(Template.java:383) ~[freemarker-2.3.30.jar!/:2.3.30]
        at org.springframework.ui.freemarker.FreeMarkerTemplateUtils.processTemplateIntoString(FreeMarkerTemplateUtils.java:50) ~[spring-context-support-5.2.10.RELEASE.jar!/:5.2.10.RELEASE]
        at cn.dustlight.captcha.sender.EmailCodeSender$DefaultTemplateProvider.getTemplateContent(EmailCodeSender.java:100) ~[email-sender-0.0.4.jar!/:0.0.4]
        at cn.dustlight.captcha.sender.EmailCodeSender.getTemplate(EmailCodeSender.java:76) ~[email-sender-0.0.4.jar!/:0.0.4]
        at cn.dustlight.captcha.sender.EmailCodeSender.send(EmailCodeSender.java:39) ~[email-sender-0.0.4.jar!/:0.0.4]
        ... 101 common frames omitted

原因为 Java 在编译时出于安全等原因的考虑,导致编译后的方法参数名并非是原参数名,而是 arg0, arg1, argN... 的形式。 在编译时添加参数 -parameters 即可保留原参数名。例如:javac -parameters XX.java

在 Maven 项目的编译选项添加配置 <arg>-parameters</arg>

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>3.3</version>
    <configuration>
        <source>1.8</source>
        <target>1.8</target>
        <compilerArgs>
            <arg>-parameters</arg>
        </compilerArgs>
    </configuration>
</plugin>