解决若依框架短信验证码登录,并且不影响原有登录

文章目录


一、实现DaoAuthenticationProvider

1.位置

2.代码部分

二、修改SecurityConfig配置

1.位置

编辑

2.代码部分

三、验证码登录方法

1.位置

2.控制层代码

3.实现类代码

4.密码不验证

5.验证码验证

6.验证码发送



一、实现DaoAuthenticationProvider

1.位置

若依框架接入mongodb 若依框架登录_spring

2.代码部分

Constants.CUSTOM_LOGIN_SMS是一个常量,随便定义一个字符串即可。

package com.ruoyi.framework.security.filter;

import com.ruoyi.common.constant.Constants;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

/**
 * 自定义登录扩展
 */
public class CustomLoginAuthenticationProvider extends DaoAuthenticationProvider {

    public CustomLoginAuthenticationProvider(UserDetailsService userDetailsService) {
        super();
        setUserDetailsService(userDetailsService);
    }

    @Override
    protected void additionalAuthenticationChecks(UserDetails userDetails, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {
        if (authentication.getCredentials() == null) {
            this.logger.debug("Authentication failed: no credentials provided");
            throw new BadCredentialsException(this.messages.getMessage("AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"));
        } else {
            String password = authentication.getCredentials().toString();
            if(Constants.CUSTOM_LOGIN_SMS.equals(password)){
                //短信登录,不验证密码
            }else{
                BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
                if (!passwordEncoder.matches(password, userDetails.getPassword())) {
                    this.logger.debug("Authentication failed: password does not match stored value");
                    throw new BadCredentialsException(this.messages.getMessage("AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"));
                }
            }
        }
    }
}

二、修改SecurityConfig配置

1.位置

2.代码部分

在最下面,复制上去即可。

/**
     * 身份认证接口
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(new CustomLoginAuthenticationProvider(userDetailsService));
        auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder());
    }

三、验证码登录方法

1.位置

若依框架接入mongodb 若依框架登录_ide_02

2.控制层代码

@PostMapping("/appCodeLogin")
    public AjaxResult appCodeLogin(@RequestBody LoginBody loginBody) {
        AjaxResult ajax = AjaxResult.success();
        // 生成令牌
        String token = loginService.appCodeLogin(loginBody.getUsername(), loginBody.getCode(), loginBody.getUuid());
        ajax.put(Constants.TOKEN, token);
        return ajax;
    }

3.实现类代码

至于位置,通过上面代码创建这个方法,在复制上即可,没有写发送验证码的,可以把第一句注释,即可只输入账号登录。

/**
     * APP验证码登录方法
     *
     * @param username 手机号
     * @param code 验证码
     * @param uuid uuid
     * @return 结果
     */
    public String appCodeLogin(String username, String code, String uuid) {
        validateCaptcha(username, code, uuid); //校验验证码
        Authentication authentication = null; // 用户验证
        try {
            UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(username, Constants.CUSTOM_LOGIN_SMS);
            AuthenticationContextHolder.setContext(authenticationToken);
            // 该方法会去调用UserDetailsServiceImpl.loadUserByUsername
            authentication = authenticationManager.authenticate(authenticationToken);
        }
        catch (Exception e) {
            if (e instanceof BadCredentialsException) {
                throw new UserPasswordNotMatchException();          //抛出账号或者密码错误的异常
            } else {
                throw new ServiceException(e.getMessage());         //抛出其他异常
            }
        } finally {
            AuthenticationContextHolder.clearContext();
        }
        LoginUser loginUser = (LoginUser) authentication.getPrincipal();
        recordLoginInfo(loginUser.getUserId());                     //修改sys_user最近登录IP和登录时间
        // 生成token
        return tokenService.createToken(loginUser);
    }

4.密码不验证

位置

若依框架接入mongodb 若依框架登录_若依框架接入mongodb_03

这个方法下面加入一个密码为Constants.CUSTOM_LOGIN_SMS不验证密码的判断

5.验证码验证

这里验证码验证就是用的若依里面写好的代码。

/**
     * 校验验证码
     * 
     * @param username 用户名
     * @param code 验证码
     * @param uuid 唯一标识
     */
    public void validateCaptcha(String username, String code, String uuid) {
        String verifyKey = CacheConstants.CAPTCHA_CODE_KEY + StringUtils.nvl(uuid, "");//验证码key值
        String captcha = redisCache.getCacheObject(verifyKey);       //拿到缓存的数据
        redisCache.deleteObject(verifyKey);//删除该缓存
        if (captcha == null) {
            //异步记录登录信息sys_logininfor
            AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire")));
            throw new CaptchaExpireException();                      //抛出一个验证码过期异常
        }
        if (!code.equalsIgnoreCase(captcha)) {
            //异步记录登录信息sys_logininfor
            AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.error")));
            throw new CaptchaException();                             //抛出一个验证码错误的异常
        }
    }

6.验证码发送

发送用户短信的方法,就不提供了,这里就是发送验证码,并存起来。

@GetMapping("/appCaptcha")
    public AjaxResult getAppCode(Long deptId,String phone) throws Exception {
        //创建一个返回对象
        AjaxResult ajax = AjaxResult.success();
        // 保存验证码信息
        String uuid = IdUtils.simpleUUID(); //生成一个uuid
        String verifyKey = CacheConstants.CAPTCHA_CODE_KEY + uuid;
        // 生成四位数验证码
        String code = RandomUtil.getFourBitRandom();
        // 查询短信参数信息
        ShortMessage shortMessage = shortMessageService.selectShortMessageByDeptId(deptId);
        // 通过阿里云短信发送短信
        boolean sent = ShortMessageUtils.sent(shortMessage, phone, code);
        //把验证码答应存入缓存,10分钟的时间
        redisCache.setCacheObject(verifyKey, code, Constants.CODE_EXPIRATION, TimeUnit.MINUTES);
        //把信息封装返回
        ajax.put("uuid", uuid);