解决若依框架短信验证码登录,并且不影响原有登录
文章目录
一、实现DaoAuthenticationProvider
1.位置
2.代码部分
二、修改SecurityConfig配置
1.位置
2.代码部分
三、验证码登录方法
1.位置
2.控制层代码
3.实现类代码
4.验证码验证
5.验证码发送
一、实现DaoAuthenticationProvider
1.位置
2.代码部分
Constants.CUSTOM_LOGIN_SMS是一个常量,随便定义一个字符串即可。
package com.ruoyi.framework.security.filter;import mon.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);}@Overrideprotected 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.代码部分
在最下面,复制上去即可。
/*** 身份认证接口*/@Overrideprotected 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.loadUserByUsernameauthentication = 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和登录时间// 生成tokenreturn tokenService.createToken(loginUser);}
4.验证码验证
这里验证码验证就是用的若依里面写好的代码。
/*** 校验验证码* * @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_logininforAsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire")));throw new CaptchaExpireException(); //抛出一个验证码过期异常}if (!code.equalsIgnoreCase(captcha)) {//异步记录登录信息sys_logininforAsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.error")));throw new CaptchaException(); //抛出一个验证码错误的异常}}
5.验证码发送
发送用户短信的方法,就不提供了,这里就是发送验证码,并存起来。
@GetMapping("/appCaptcha")public AjaxResult getAppCode(Long deptId,String phone) throws Exception {//创建一个返回对象AjaxResult ajax = AjaxResult.success();// 保存验证码信息String uuid = IdUtils.simpleUUID(); //生成一个uuidString 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);