SpringCloud微服务实战——搭建企业级开发框架(二十四):集成行为验证码和图片验证码实现登录功能

本文介绍了如何在GitEgg-Cloud项目中集成AJ-Captcha滑动验证码和EasyCaptcha图片验证码,通过配置项选择使用方式。详细步骤包括添加依赖、创建CaptchaCacheServiceRedisImpl实现缓存、自定义CaptchaTokenGranter令牌授权处理类、提供验证码相关API以及在Nacos中配置默认验证码类型。这一增强提升了系统的安全性与用户体验。
摘要由CSDN通过智能技术生成

随着近几年技术的发展,人们对于系统安全性和用户体验的要求越来越高,大多数网站系统都逐渐采用行为验证码来代替图片验证码。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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值