AJ-Captcha:轻松集成图形验证码

开发 前端
为了保护网站和服务免受恶意机器人的侵扰,验证码(Captcha)技术应运而生。AJ-Captcha 是一种高效、安全且易于集成的验证码解决方案,本文将详细介绍AJ-Captcha 的技术原理、实现方式及其应用场景。

引言

随着互联网的快速发展,各种在线服务和应用变得越来越普及,同时也带来了大量的自动化攻击和滥用行为。为了保护网站和服务免受恶意机器人的侵扰,验证码(Captcha)技术应运而生。AJ-Captcha 是一种高效、安全且易于集成的验证码解决方案,本文将详细介绍AJ-Captcha 的技术原理、实现方式及其应用场景。

应用场景

  • 注册登录保护:在用户注册账号或登录已有账户时启用AJ-Captcha,可以有效阻止恶意注册和暴力破解尝试。
  • 表单提交防护:对于那些容易受到大量垃圾信息骚扰的在线表格(如反馈建议、活动报名等),添加AJ-Captcha能显著降低无效数据量。
  • 支付确认环节:在涉及资金交易的关键步骤加入额外的身份验证措施,确保每笔订单都出自合法用户之手。
  • 资源下载限制:对于一些珍贵资料或者受版权保护的内容,可以通过设置AJ-Captcha作为下载前的最后一道防线,防止未经授权的批量抓取。

具体实现

1.依赖引入

<!-- redis -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- captcha 图形验证码-->
<dependency>
    <groupId>com.anji-plus</groupId>
    <artifactId>spring-boot-starter-captcha</artifactId>
    <version>1.3.0</version>
</dependency>

2.配置yml

server:
  port: 10001
# 数据库配置
spring:
  datasource:
    driver-class-name: com.kingbase8.Driver
    url: jdbc:kingbase8://localhost:54321/test?currentSchema=public
    username: system
    password: root
  redis:
    host: localhost
    password: yianweilai
    port: 6379
    
# Anji-plus 验证码配置
aj:
  captcha:
    # 缓存类型
    cache-type: redis
    # blockPuzzle 滑块 clickWord 文字点选  default默认两者都实例化
    type: clickWord
    # 校验滑动拼图允许误差偏移量(默认5像素)
    slip-offset: 5
    # aes加密坐标开启或者禁用(true|false)
    aes-status: true
    # 滑动干扰项(0/1/2)
    interference-options: 0
    # 右下角水印
    water-mark: "一安未来"

3.配置Redis和Captcha

@Configuration
public class RedisConfig {

    @Resource
    private RedisConnectionFactory factory;

    @Bean
    public RedisTemplate<String, Object> redisTemplate() {
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(factory);
        GenericJackson2JsonRedisSerializer genericJackson2JsonRedisSerializer = new GenericJackson2JsonRedisSerializer();
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
        redisTemplate.setKeySerializer(stringRedisSerializer);
        redisTemplate.setValueSerializer(genericJackson2JsonRedisSerializer);
        redisTemplate.setHashKeySerializer(stringRedisSerializer);
        redisTemplate.setHashValueSerializer(genericJackson2JsonRedisSerializer);
        redisTemplate.afterPropertiesSet();
        return redisTemplate;
    }
}
@Service
public class CaptchaCacheServiceRedis implements CaptchaCacheService {

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Override
    public String type() {
        return "redis";
    }

    @Override
    public void set(String key, String value, long expiresInSeconds) {
        stringRedisTemplate.opsForValue().set(key, value, expiresInSeconds, TimeUnit.SECONDS);
    }

    @Override
    public boolean exists(String key) {
        return stringRedisTemplate.hasKey(key);
    }

    @Override
    public void delete(String key) {
        stringRedisTemplate.delete(key);
    }

    @Override
    public String get(String key) {
        return stringRedisTemplate.opsForValue().get(key);
    }
}

4.加载服务实现

在 resources 目录下新建 META-INF/services,在 services 目录下新建 com.anji.captcha.service.CaptchaCacheService 的文件,内容指向 CaptchaCacheService 的配置路径。

5.编写首页

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>验证码示例</title>
    <link rel="stylesheet" type="text/css"  href="/css/bootstrap.min.css">
    <link rel="stylesheet" type="text/css" href="/css/verify.css">
    <script src="/js/jquery.min.js"></script>
    <script src="/js/crypto-js.js"></script>
    <script src="/js/ase.js"></script>
    <script src="/js/verify.js"></script>
    <style>
        body {
            display: flex;
            flex-direction: column;
            justify-content: center;
            align-items: center;
            height: 100vh;
        }

        .container {
            margin-top: -80px;
            width: 78%;
            display: flex;
            flex-direction: column;
            justify-content: center;
            align-items: center;
            border-radius: 10px;
            border: 1px solid gray;
            padding: 25px;
        }

        form {
            width: 80%;
        }

        .btn {
            border: none;
            outline: none;
            width: 300px;
            height: 40px;
            line-height: 40px;
            text-align: center;
            cursor: pointer;
            background-color: #409EFF;
            color: #fff;
            font-size: 16px;
            letter-spacing: 1em;
        }

    </style>
</head>
<body>

<div class="container">
    <h2>请登录</h2>
    <form th:action="@{/login}" method="post">
        <div class="form-group">
            <label for="username">用户名</label>
            <input type="text" class="form-control" id="username" name="username" />
        </div>
        <div class="form-group">
            <label for="password">密码</label>
            <input type="password" class="form-control" id="password" name="password" />
        </div>
        <div class="form-group">
            <button class="btn btn-primary" id='btn' type="button" >登录</button>
            <div id="mpanel" style="margin-top:50px;"></div>
            <div id="tip" style="margin-top:50px;"></div>
        </div>
    </form>
</div>

<script>
    //slideVerify 对应blockPuzzle模式
    //pointsVerify 对应clickWord模式
    $('#mpanel').pointsVerify({
        baseUrl: 'http://localhost:10001',
        mode: 'pop',
        containerId: 'btn',//pop模式 必填 被点击之后出现行为验证码的元素id
        imgSize: {
            width: '400px',
            height: '200px'
        },
        barSize: {
            width: '400px',
            height: '40px'
        },
        beforeCheck: function () {
            var name = $("#username").val();
            var pass = $('#password').val();
            if (name === '' || pass === '') {
                $("#tip").html('<div class="alert alert-danger">请输入用户名和密码!</div>');
                setTimeout(function() {
                    $("#tip div.alert").fadeOut(500);
                }, 5000);
                return false;
            }
            return true;
        },
        ready: function () {},
        success: function (params) {
            var name = $("#username").val();
            var pass = $('#password').val();
            $.ajax({
                type: "POST",
                url: "/login",
                data: {
                    username: name,
                    password: pass
                },
                success: function (response) {
                    if (response.success) {
                        $("#tip").html('<div class="alert alert-success">登录成功</div>');
                    } else {
                        $("#tip").html('<div class="alert alert-danger">登录失败</div>');
                    }
                    setTimeout(function() {
                        $("#tip div.alert").fadeOut(500);
                    }, 5000);
                },
                error: function () {
                    $("#tip").html('<div class="alert alert-danger">登录请求出错</div>');
                    setTimeout(function() {
                        $("#tip div.alert").fadeOut(500);
                    }, 5000);
                }
            });
        },
        error: function () {}
    });
</script>
</body>
</html>

6.实际效果
图片 图片

责任编辑:武晓燕 来源: 一安未来
相关推荐

2013-10-29 13:31:36

2020-12-29 05:33:03

Serverless验证码架构

2009-11-23 16:59:23

PHP图形验证码

2015-12-11 09:54:47

2013-06-19 10:19:59

2020-12-20 10:07:57

Canvas图形验证码javascript

2020-11-16 07:28:53

验证码

2015-03-23 17:58:04

验证码倒计时并行

2017-12-21 07:38:19

2015-09-21 15:31:05

php实现验证码

2022-02-11 07:10:15

验证码

2021-01-19 10:29:34

短信验证码密码

2009-08-11 14:05:28

JSP验证码

2009-02-09 14:17:36

2018-08-28 08:28:29

验证码服务器漏洞

2015-03-17 09:28:04

2019-06-18 07:12:25

验证码漏洞加密

2011-11-02 16:46:41

2011-11-02 12:43:33

点赞
收藏

51CTO技术栈公众号