随着近几年技术的发展,人们对于系统安全性和用户体验的要求越来越高,大多数网站系统都逐渐采用行为验证码来代替图片验证码。GitEgg-Cloud集成了开源行为验证码组件和图片验证码,并在系统中添加可配置项来选择具体使用哪种验证码。
AJ-Captcha:行为验证码
EasyCaptcha: 图片验证码
1、在我们的gitegg-platform-bom工程中增加验证码的包依赖
<!-- AJ-Captcha滑动验证码 -->
<captcha.version>1.2.7</captcha.version>
<!-- Easy-Captcha图形验证码 -->
<easy.captcha.version>1.6.2</easy.captcha.version>
<!-- captcha 滑动验证码-->
<dependency>
<groupid>com.github.anji-plus</groupid>
<artifactid>captcha-spring-boot-starter</artifactid>
<version>${captcha.version}</version>
</dependency>
<!-- easy-captcha 图形验证码-->
<dependency>
<groupid>com.github.whvcse</groupid>
<artifactid>easy-captcha</artifactid>
<version>${easy.captcha.version}</version>
</dependency>
2、新建gitegg-platform-captcha工程,用于配置及自定义方法,行为验证码用到缓存是需要自定义实现CaptchaCacheService,自定义类CaptchaCacheServiceRedisImpl:
public class CaptchaCacheServiceRedisImpl implements CaptchaCacheService {
@Override
public String type() {
return "redis";
}
@Autowired
private StringRedisTemplate stringRedisTemplate;
@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);
}
}
3、在gitegg-platform-captcha的resources目录新建META-INF.services文件夹,参考resource/META-INF/services中的写法。
com.gitegg.platform.captcha.service.impl.CaptchaCacheServiceRedisImpl
4、在GitEgg-Cloud下的gitegg-oauth中增加CaptchaTokenGranter自定义验证码令牌授权处理类
/**
-
验证码模式
*/
public class CaptchaTokenGranter extends AbstractTokenGranter {private static final String GRANT_TYPE = “captcha”;
private final AuthenticationManager authenticationManager;
private RedisTemplate redisTemplate;
private CaptchaService captchaService;
private String captchaType;
public CaptchaTokenGranter(AuthenticationManager authenticationManager,
AuthorizationServerTokenServices tokenServices, ClientDetailsService clientDetailsService,
OAuth2RequestFactory requestFactory, RedisTemplate redisTemplate, CaptchaService captchaService,
String captchaType) {
this(authenticationManager, tokenServices, clientDetailsService, requestFactory, GRANT_TYPE);
this.redisTemplate = redisTemplate;
this.captchaService = captchaService;
this.captchaType = captchaType;
}protected CaptchaTokenGranter(AuthenticationManager authenticationManager,
AuthorizationServerTokenServices tokenServices, ClientDetailsService clientDetailsService,
OAuth2RequestFactory requestFactory, String grantType) {
super(tokenServices, clientDetailsService, requestFactory, grantType);
this.authenticationManager = authenticationManager;
}@Override
protected OAuth2Authentication getOAuth2Authentication(ClientDetails client, TokenRequest tokenRequest) {
Map<string, string=""> parameters = new LinkedHashMap<>(tokenRequest.getRequestParameters());
// 获取验证码类型
String captchaType = parameters.get(CaptchaConstant.CAPTCHA_TYPE);// 判断传入的验证码类型和系统配置的是否一致 if (!StringUtils.isEmpty(captchaType) && !captchaType.equals(this.captchaType)) { throw new UserDeniedAuthorizationException(ResultCodeEnum.INVALID_CAPTCHA_TYPE.getMsg()); } if (CaptchaConstant.IMAGE_CAPTCHA.equalsIgnoreCase(captchaType)) { // 图片验证码验证 String captchaKey = parameters.get(CaptchaConstant.CAPTCHA_KEY); String captchaCode = parameters.get(CaptchaConstant.CAPTCHA_CODE); // 获取验证码 String redisCode = (String)redisTemplate.opsForValue().get(CaptchaConstant.IMAGE_CAPTCHA_KEY + captchaKey); // 判断验证码 if (captchaCode == null || !captchaCode.equalsIgnoreCase(redisCode)) { throw new UserDeniedAuthorizationException(ResultCodeEnum.INVALID_CAPTCHA.getMsg()); } } else { // 滑动验证码验证 String captchaVerification = parameters.get(CaptchaConstant.CAPTCHA_VERIFICATION); String slidingCaptchaType = parameters.get(CaptchaConstant.SLIDING_CAPTCHA_TYPE); CaptchaVO captchaVO = new CaptchaVO(); captchaVO.setCaptchaVerification(captchaVerification); captchaVO.setCaptchaType(slidingCaptchaType); ResponseModel responseModel = captchaService.verification(captchaVO); if (null == responseModel || !RepCodeEnum.SUCCESS.getCode().equals(responseModel.getRepCode())) { throw new UserDeniedAuthorizationException(ResultCodeEnum.INVALID_CAPTCHA.getMsg()); } } String username = parameters.get(TokenConstant.USER_NAME); String password = parameters.get(TokenConstant.PASSWORD); // Protect from downstream leaks of password parameters.remove(TokenConstant.PASSWORD); Authentication userAuth = new UsernamePasswordAuthenticationToken(username, password); ((AbstractAuthenticationToken)userAuth).setDetails(parameters); try { userAuth = authenticationManager.authenticate(userAuth); } catch (AccountStatusException | BadCredentialsException ase) { // covers expired, locked, disabled cases (mentioned in section 5.2, draft 31) throw new InvalidGrantException(ase.getMessage()); } // If the username/password are wrong the spec says we should send 400/invalid grant if (userAuth == null || !userAuth.isAuthenticated()) { throw new InvalidGrantException("Could not authenticate user: " + username); } OAuth2Request storedOAuth2Request = getRequestFactory().createOAuth2Request(client, tokenRequest); return new OAuth2Authentication(storedOAuth2Request, userAuth);
}
}
5、gitegg-oauth中GitEggOAuthController新增获取验证码的方法@Value("${captcha.type}")
private String captchaType;@ApiOperation(“获取系统配置的验证码类型”)
@GetMapping("/captcha/type")
public Result captchaType() {
return Result.data(captchaType);
}@ApiOperation(“生成滑动验证码”)
@PostMapping("/captcha")
public Result captcha(@RequestBody CaptchaVO captchaVO) {
ResponseModel responseModel = captchaService.get(captchaVO);
return Result.data(responseModel);
}@ApiOperation(“滑动验证码验证”)
@PostMapping("/captcha/check")
public Result captchaCheck(@RequestBody CaptchaVO captchaVO) {
ResponseModel responseModel = captchaService.check(captchaVO);
return Result.data(responseModel);
}@ApiOperation(“生成图片验证码”)
@RequestMapping("/captcha/image")
public Result captchaImage() {
SpecCaptcha specCaptcha = new SpecCaptcha(130, 48, 5);
String captchaCode = specCaptcha.text().toLowerCase();
String captchaKey = UUID.randomUUID().toString();
// 存入redis并设置过期时间为5分钟
redisTemplate.opsForValue().set(CaptchaConstant.IMAGE_CAPTCHA_KEY + captchaKey, captchaCode, GitEggConstant.Number.FIVE,
TimeUnit.MINUTES);
ImageCaptcha imageCaptcha = new ImageCaptcha();
imageCaptcha.setCaptchaKey(captchaKey);
imageCaptcha.setCaptchaImage(specCaptcha.toBase64());
// 将key和base64返回给前端
return Result.data(imageCaptcha);
}
6、将滑动验证码提供的前端页面verifition目录copy到我们前端工程的compoonents目录,修改Login.vue,增加验证码
}
7、在Nacos中增加配置项,默认使用行为验证码
#验证码配置
captcha:
#验证码的类型 sliding: 滑动验证码 image: 图片验证码
type: sliding
8、登录效果
亚马逊测评 www.yisuping.cn