SpringBoot 前后端分离 集成图形验证码

578 阅读4分钟

专栏文章

springboot前后端分离项目集成Security框架和JWT完成用户校验

前言

在如今数字化的时代,保护用户信息和防止恶意攻击是每个网站和应用程序的重要任务之一。图形验证码是一种常见的验证机制,用于验证用户的真实性并防止自动化攻击。通过集成图形验证码到Spring Boot应用程序中,我们可以有效地增加安全性和保护用户数据。

本文章将为您介绍如何在Sprimng Boo应用程序中集成图形验证码功能,我们将使用Google的kaptcha库,该库提供了一个简单而强大的方式来生成图形验证妈,并且可以自定义验证码的样式和参数

在本文中,我们将一步一步地指导您如何在Spring Boot中引入kaptcha库,并配置验证码生成器。我们还将展示如何在用户注册和登录功能中使用验证码,以确保只有真实用户才能访问敏感信息或执行关键提作。通过该验证码功能的集成我们可以提高应用程序的安全性,防止自动化攻击,并增强用户体验。

无论您是新手还是有经验的开发人员,本文都将为您提供一个清晰的指南帮助您轻松地集成图形验证码功能到Spring Boot应用程序中。您将学习到如何配置验证码生成器,如何显示验证码图片,以及如何验证用户提交的验证码是否正确

让我们开始吧,一起学习如何在Spring Boot应用程序中集成图形验证码功能,提高应用程序的安全性和用户体验。

1. 引入必要依赖

<!-- 验证码 -->
<dependency>
  <groupId>pro.fessional</groupId>
  <artifactId>kaptcha</artifactId>
  <version>2.3.3</version>
</dependency>
<!-- redis 缓存操作 -->
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

2. 配置文件

/**
 * 验证码配置
 *
 * @author fanglei
 */
@Configuration
public class CaptchaConfig
{
    @Bean(name = "captchaProducer")
    public DefaultKaptcha getKaptchaBean()
    {
        DefaultKaptcha defaultKaptcha = new DefaultKaptcha();
        Properties properties = new Properties();
        // 是否有边框 默认为true 我们可以自己设置yes,no
        properties.setProperty(KAPTCHA_BORDER, "yes");
        // 验证码文本字符颜色 默认为Color.BLACK
        properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_COLOR, "black");
        // 验证码图片宽度 默认为200
        properties.setProperty(KAPTCHA_IMAGE_WIDTH, "160");
        // 验证码图片高度 默认为50
        properties.setProperty(KAPTCHA_IMAGE_HEIGHT, "60");
        // 验证码文本字符大小 默认为40
        properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_SIZE, "38");
        // KAPTCHA_SESSION_KEY
        properties.setProperty(KAPTCHA_SESSION_CONFIG_KEY, "kaptchaCode");
        // 验证码文本字符长度 默认为5
        properties.setProperty(KAPTCHA_TEXTPRODUCER_CHAR_LENGTH, "4");
        // 验证码文本字体样式 默认为new Font("Arial", 1, fontSize), new Font("Courier", 1, fontSize)
        properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_NAMES, "Arial,Courier");
        // 图片样式 水纹com.google.code.kaptcha.impl.WaterRipple 鱼眼com.google.code.kaptcha.impl.FishEyeGimpy 阴影com.google.code.kaptcha.impl.ShadowGimpy
        properties.setProperty(KAPTCHA_OBSCURIFICATOR_IMPL, "com.google.code.kaptcha.impl.ShadowGimpy");
        Config config = new Config(properties);
        defaultKaptcha.setConfig(config);
        return defaultKaptcha;
    }

    @Bean(name = "captchaProducerMath")
    public DefaultKaptcha getKaptchaBeanMath()
    {
        DefaultKaptcha defaultKaptcha = new DefaultKaptcha();
        Properties properties = new Properties();
        // 是否有边框 默认为true 我们可以自己设置yes,no
        properties.setProperty(KAPTCHA_BORDER, "yes");
        // 边框颜色 默认为Color.BLACK
        properties.setProperty(KAPTCHA_BORDER_COLOR, "105,179,90");
        // 验证码文本字符颜色 默认为Color.BLACK
        properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_COLOR, "blue");
        // 验证码图片宽度 默认为200
        properties.setProperty(KAPTCHA_IMAGE_WIDTH, "160");
        // 验证码图片高度 默认为50
        properties.setProperty(KAPTCHA_IMAGE_HEIGHT, "60");
        // 验证码文本字符大小 默认为40
        properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_SIZE, "35");
        // KAPTCHA_SESSION_KEY
        properties.setProperty(KAPTCHA_SESSION_CONFIG_KEY, "kaptchaCodeMath");
        // 验证码文本生成器
        properties.setProperty(KAPTCHA_TEXTPRODUCER_IMPL, "com.fang.common.config.KaptchaTextCreator");
        // 验证码文本字符间距 默认为2
        properties.setProperty(KAPTCHA_TEXTPRODUCER_CHAR_SPACE, "3");
        // 验证码文本字符长度 默认为5
        properties.setProperty(KAPTCHA_TEXTPRODUCER_CHAR_LENGTH, "6");
        // 验证码文本字体样式 默认为new Font("Arial", 1, fontSize), new Font("Courier", 1, fontSize)
        properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_NAMES, "Arial,Courier");
        // 验证码噪点颜色 默认为Color.BLACK
        properties.setProperty(KAPTCHA_NOISE_COLOR, "white");
        // 干扰实现类
        properties.setProperty(KAPTCHA_NOISE_IMPL, "com.google.code.kaptcha.impl.NoNoise");
        // 图片样式 水纹com.google.code.kaptcha.impl.WaterRipple 鱼眼com.google.code.kaptcha.impl.FishEyeGimpy 阴影com.google.code.kaptcha.impl.ShadowGimpy
        properties.setProperty(KAPTCHA_OBSCURIFICATOR_IMPL, "com.google.code.kaptcha.impl.ShadowGimpy");
        Config config = new Config(properties);
        defaultKaptcha.setConfig(config);
        return defaultKaptcha;
    }
}

3. 自定义异常

/**
 * 验证码错误异常类
 *
 * @author fanglei
 */
public class CaptchaException extends BaseException
{
    private static final long serialVersionUID = 1L;

    public CaptchaException()
    {
        super("captcha.error.input", null);
    }
}
/**
 * 验证码失效异常类
 *
 * @author fanglei
 */
public class CaptchaExpireException extends UserException
{
    private static final long serialVersionUID = 1L;

    public CaptchaExpireException()
    {
        super("captcha.error.expire", null);
    }
}

4. 配置接口

本文引入了redis 将生成一个UUID和验证码一起缓存进行判断

/**
* 验证码操作处理
*
* @author fanglei
*/
@RestController
    @Api(tags = "验证码模块")
    public class CaptchaController
{
    @Resource(name = "captchaProducer")
    private Producer captchaProducer;

    @Resource(name = "captchaProducerMath")
    private Producer captchaProducerMath;

    @Autowired
    private RedisCache redisCache;


    /**
* 生成验证码
*/
    @GetMapping("/code")
    @ApiOperation(value = "获取验证码")
    public ApiResult getCode(HttpServletResponse response) throws IOException
    {
        Map map =new HashMap();
            map.put("captchaEnabled", captchaEnabled);
        if (!captchaEnabled)
        {
            return map;
        }

        // 保存验证码信息
        String uuid = IdUtils.simpleUUID();
        String verifyKey = CacheConstants.CAPTCHA_CODE_KEY + uuid;

        String capStr = null, code = null;
        BufferedImage image = null;

        // 生成验证码 类型 char 或 math
        String captchaType = SmartLaboratoryConfig.getCaptchaType();
        if ("math".equals(captchaType))
        {
            String capText = captchaProducerMath.createText();
            capStr = capText.substring(0, capText.lastIndexOf("@"));
            code = capText.substring(capText.lastIndexOf("@") + 1);
            image = captchaProducerMath.createImage(capStr);
        }
        else if ("char".equals(captchaType))
        {
            capStr = code = captchaProducer.createText();
            image = captchaProducer.createImage(capStr);
        }

        redisCache.setCacheObject(verifyKey, code, Constants.CAPTCHA_EXPIRATION, TimeUnit.MINUTES);
        // 转换流信息写出
        FastByteArrayOutputStream os = new FastByteArrayOutputStream();
        try
            {
                ImageIO.write(image, "jpg", os);
            }
        catch (IOException e)
            {
                return AjaxResult.error(e.getMessage());
            }

        map.put("uuid", uuid);
        map.put("img", Base64.encode(os.toByteArray()));
        return ApiResult.success(map);
    }
}

5. 用户登录时校验验证码

从redis内根据UUID获取到缓存的验证码进行判断

    /**
     * 校验验证码
     *
     * @param username 用户名
     * @param code     验证码
     * @param uuid     唯一标识
     * @return 结果
     */
    public void checkCaptcha(String username, String code, String uuid) {
        boolean captchaEnabled = configService.selectCaptchaEnabled();
        if (captchaEnabled) {
            String verifyKey = CacheConstants.CAPTCHA_CODE_KEY + StringUtils.nvl(uuid, "");
            String captcha = redisCache.getCacheObject(verifyKey);
            redisCache.deleteObject(verifyKey);
            if (captcha == null) {
                throw new CaptchaExpireException();
            }
            if (!code.equalsIgnoreCase(captcha)) {
                throw new CaptchaException();
            }
        }
    }

6. 总结

以上就是简单的集成图形验证码做登陆限制