开发喵星球

ruoyi-vue 集成aj-captcha实现滑块验证码(257)

需求提出

集成滑块验证码(aj-captcha)到若依分离版项目中,以提升登录安全性。本文将详细介绍如何在若依项目中集成aj-captcha,实现滑块验证码功能。

相关介绍

aj-captcha 是一个基于 Spring Boot 的滑块验证码实现组件,支持滑块拼图和文字点选两种验证码类型。它提供了简单易用的API和丰富的配置项,有效防止恶意登录和暴力破解,可以满足不同场景下的需求。

解决思路

  1. 添加aj-captcha依赖。
  2. 配置aj-captcha相关参数。
  3. 修改SecurityConfig,设置滑块验证码相关接口的匿名访问。
  4. 修改登录逻辑,集成滑块验证码校验。
  5. 实现Redis缓存服务,用于存储验证码信息。
  6. 在前端集成滑块验证码插件。

所需技术

项目结构树

├── ruoyi-admin
│   ├── src\main\java
│   │   └── com\ruoyi\web\controller\common
│   │       └── CaptchaController.java
│   └── resources
│       ├── application.yml
│       └── META-INF
│           └── services
│               └── com.anji.captcha.service.CaptchaCacheService
├── ruoyi-framework
│   ├── pom.xml
│   └── src\main\java
│       └── com\ruoyi\framework
│           ├── web
│           │   ├── service
│           │   │   ├── CaptchaRedisService.java
│           │   │   └── SysLoginService.java
│           │   └── controller
│           │       └── system
│           │           └── SysLoginController.java
│           └── config
│               └── SecurityConfig.java
└── ruoyi-ui

注意事项

完整代码(分步骤)

第一步:添加aj-captcha依赖

ruoyi-framework/pom.xml 文件中添加aj-captcha依赖:

<!-- 滑块验证码  -->
<dependency>
    <groupId>com.github.anji-plus</groupId>
    <artifactId>captcha-spring-boot-starter</artifactId>
    <version>1.2.7</version>
</dependency>

<!-- 原有的验证码kaptcha依赖不需要可以删除  -->

第二步:修改application.yml,加入aj-captcha配置

# 滑块验证码
aj:
   captcha:
      # 缓存类型
      cache-type: redis
      # blockPuzzle 滑块 clickWord 文字点选  default默认两者都实例化
      type: blockPuzzle
      # 右下角显示字
      water-mark: ruoyi.vip
      # 校验滑动拼图允许误差偏移量(默认5像素)
      slip-offset: 5
      # aes加密坐标开启或者禁用(true|false)
      aes-status: true
      # 滑动干扰项(0/1/2)
      interference-options: 2

ruoyi-admin/src/main/resources/META-INF/services 目录下创建 com.anji.captcha.service.CaptchaCacheService 文件,内容如下:

com.ruoyi.framework.web.service.CaptchaRedisService

第三步:在SecurityConfig中设置httpSecurity配置匿名访问

确保滑块验证码相关接口可以匿名访问。在 ruoyi-framework/src/main/java/com/ruoyi/framework/config/SecurityConfig.java 文件中添加如下配置:

.antMatchers("/login", "/captcha/get", "/captcha/check").permitAll()

第四步:修改相关类

移除原先不需要的类:

修改 ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysLoginController.java

/**
 * 登录方法
 * 
 * @param loginBody 登录信息
 * @return 结果
 */
@PostMapping("/login")
public AjaxResult login(@RequestBody LoginBody loginBody)
{
    AjaxResult ajax = AjaxResult.success();
    // 生成令牌
    String token = loginService.login(loginBody.getUsername(), loginBody.getPassword(), loginBody.getCode());
    ajax.put(Constants.TOKEN, token);
    return ajax;
}

修改 ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/SysLoginService.java

package com.ruoyi.framework.web.service;

import javax.annotation.Resource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Component;
import com.anji.captcha.model.common.ResponseModel;
import com.anji.captcha.model.vo.CaptchaVO;
import com.anji.captcha.service.CaptchaService;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.exception.user.CaptchaException;
import com.ruoyi.common.exception.user.UserPasswordNotMatchException;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.MessageUtils;
import com.ruoyi.common.utils.ServletUtils;
import com.ruoyi.common.utils.ip.IpUtils;
import com.ruoyi.framework.manager.AsyncManager;
import com.ruoyi.framework.manager.factory.AsyncFactory;
import com.ruoyi.framework.security.context.AuthenticationContextHolder;
import com.ruoyi.system.service.ISysUserService;

/**
 * 登录校验方法
 * 
 * @author ruoyi
 */
@Component
public class SysLoginService
{
    @Autowired
    private TokenService tokenService;

    @Resource
    private AuthenticationManager authenticationManager;

    @Autowired
    private ISysUserService userService;

    @Autowired
    @Lazy
    private CaptchaService captchaService;

    /**
     * 登录验证
     * 
     * @param username 用户名
     * @param password 密码
     * @param code 验证码
     * @return 结果
     */
    public String login(String username, String password, String code)
    {
        CaptchaVO captchaVO = new CaptchaVO();
        captchaVO.setCaptchaVerification(code);
        ResponseModel response = captchaService.verification(captchaVO);
        if (!response.isSuccess())
        {
            AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.error")));
            throw new CaptchaException();
        }
        // 用户验证
        Authentication authentication = null;
        try
        {
            UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(username, password);
            AuthenticationContextHolder.setContext(authenticationToken);
            // 该方法会去调用UserDetailsServiceImpl.loadUserByUsername
            authentication = authenticationManager.authenticate(authenticationToken);
        }
        catch (Exception e)
        {
            if (e instanceof BadCredentialsException)
            {
                AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match")));
                throw new UserPasswordNotMatchException();
            }
            else
            {
                AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, e.getMessage()));
                throw new ServiceException(e.getMessage());
            }
        }
        finally
        {
            AuthenticationContextHolder.clearContext();
        }
        AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success")));
        LoginUser loginUser = (LoginUser) authentication.getPrincipal();
        recordLoginInfo(loginUser.getUserId());
        // 生成token
        return tokenService.createToken(loginUser);
    }

    /**
     * 记录登录信息
     *
     * @param userId 用户ID
     */
    public void recordLoginInfo(Long userId)
    {
        SysUser sysUser = new SysUser();
        sysUser.setUserId(userId);
        sysUser.setLoginIp(IpUtils.getIpAddr(ServletUtils.getRequest()));
        sysUser.setLoginDate(DateUtils.getNowDate());
        userService.updateUserProfile(sysUser);
    }
}

新增 ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/CaptchaRedisService.java

package com.ruoyi.framework.web.service;

import java.util.concurrent.TimeUnit;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import com.anji.captcha.service.CaptchaCacheService;

/**
 * 自定义redis验证码缓存实现类
 * 
 * @author ruoyi
 */
public class CaptchaRedisService implements CaptchaCacheService
{
    @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);
    }

    @Override
    public Long increment(String key, long val)
    {
        return stringRedisTemplate.opsForValue().increment(key, val);
    }

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

第五步:添加滑动验证码插件到ruoyi-ui

下载前端插件相关包和代码实现:ruoyi-vue/集成滑动验证码.zip

链接: https://pan.baidu.com/s/1mntMUD7I64fwMGk2Li74sw
提取码: meow

运行结果

通过上述步骤,成功集成了aj-captcha滑块验证码到若依分离版项目中。启动项目后,可以在登录页面看到滑块验证码,并通过滑动验证完成登录操作。

总结

本文详细介绍了如何在若依分离版项目中集成aj-captcha滑块验证码。通过添加依赖、配置参数、修改登录逻辑和前端集成插件,实现了滑块验证码功能。希望本次教程对你有所帮助。如果在集成过程中遇到问题,可以合理利用搜索引擎工具,问题终会解决的。

   
分类:Java/OOP 作者:无限繁荣, 吴蓉 发表于:2024-06-30 22:16:34 阅读量:181
<<   >>


powered by kaifamiao