资源下载限制:对于一些珍贵资料或者受版权保护的内容,可以通过设置AJ-Captcha作为下载前的最后一道防线,防止未经授权的批量抓取。
<!-- 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.加载服务实现
<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>堆代码 duidaima.com</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.实际效果