若依短信验证码登录

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

文章目录


一、实现DaoAuthenticationProvider

1.位置

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.位置

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.密码不验证

位置

这个方法下面加入一个密码为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);
       

  • 11
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 15
    评论
短信验证码登录是一种通过发送短信验证码来验证用户身份的登录方式。具体实现的思路如下: 1. 用户在登录页面输入手机号码,并点击发送验证码按钮。 2. 后台接收到手机号码后,生成一个随机的验证码,并将验证码发送到用户的手机上。 3. 后台将生成的验证码存储在session中,以便后续验证使用。 4. 用户在手机上收到验证码后,输入验证码并点击登录按钮。 5. 后台接收到用户输入的验证码后,与session中存储的验证码进行比较。 6. 如果验证码匹配成功,则认为用户身份验证通过,可以进行登录操作。 7. 如果验证码匹配失败,则返回错误信息,要求用户重新输入验证码。 在具体的代码实现中,可以使用第三方短信服务提供商的API来发送短信验证码,比如榛子云。发送短信验证码的代码可以参考引用[2]中的示例代码。而验证码的验证可以参考引用[3]中的示例代码。 需要注意的是,为了保证安全性,验证码应该有一定的有效期限,并且在验证成功后应该立即从session中删除,以防止被恶意利用。此外,还可以考虑添加一些额外的安全措施,比如限制验证码的发送频率、添加图形验证码等。 总结起来,短信验证码登录是一种安全、方便的登录方式,通过发送短信验证码来验证用户身份,可以有效防止恶意登录和账号被盗用的风险。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 15
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

予风北

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值