若依短信验证码登录
解決若依框架短信驗(yàn)證碼登錄,并且不影響原有登錄
文章目錄
一、實(shí)現(xiàn)DaoAuthenticationProvider
1.位置
2.代碼部分
二、修改SecurityConfig配置
1.位置
2.代碼部分
?三、驗(yàn)證碼登錄方法
1.位置
2.控制層代碼
3.實(shí)現(xiàn)類代碼
4.驗(yàn)證碼驗(yàn)證
5.驗(yàn)證碼發(fā)送
一、實(shí)現(xiàn)DaoAuthenticationProvider
1.位置
2.代碼部分
Constants.CUSTOM_LOGIN_SMS是一個(gè)常量,隨便定義一個(gè)字符串即可。
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;/*** 自定義登錄擴(kuò)展*/ 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)){//短信登錄,不驗(yàn)證密碼}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.代碼部分
在最下面,復(fù)制上去即可。
/*** 身份認(rèn)證接口*/@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {auth.authenticationProvider(new CustomLoginAuthenticationProvider(userDetailsService));auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder());}三、驗(yàn)證碼登錄方法
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.實(shí)現(xiàn)類代碼
至于位置,通過上面代碼創(chuàng)建這個(gè)方法,在復(fù)制上即可,沒有寫發(fā)送驗(yàn)證碼的,可以把第一句注釋,即可只輸入賬號(hào)登錄。
/*** APP驗(yàn)證碼登錄方法** @param username 手機(jī)號(hào)* @param code 驗(yàn)證碼* @param uuid uuid* @return 結(jié)果*/public String appCodeLogin(String username, String code, String uuid) {validateCaptcha(username, code, uuid); //校驗(yàn)驗(yàn)證碼Authentication authentication = null; // 用戶驗(yàn)證try {UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(username, Constants.CUSTOM_LOGIN_SMS);AuthenticationContextHolder.setContext(authenticationToken);// 該方法會(huì)去調(diào)用UserDetailsServiceImpl.loadUserByUsernameauthentication = authenticationManager.authenticate(authenticationToken);}catch (Exception e) {if (e instanceof BadCredentialsException) {throw new UserPasswordNotMatchException(); //拋出賬號(hào)或者密碼錯(cuò)誤的異常} else {throw new ServiceException(e.getMessage()); //拋出其他異常}} finally {AuthenticationContextHolder.clearContext();}LoginUser loginUser = (LoginUser) authentication.getPrincipal();recordLoginInfo(loginUser.getUserId()); //修改sys_user最近登錄IP和登錄時(shí)間// 生成tokenreturn tokenService.createToken(loginUser);}4.驗(yàn)證碼驗(yàn)證
這里驗(yàn)證碼驗(yàn)證就是用的若依里面寫好的代碼。
/*** 校驗(yàn)驗(yàn)證碼* * @param username 用戶名* @param code 驗(yàn)證碼* @param uuid 唯一標(biāo)識(shí)*/public void validateCaptcha(String username, String code, String uuid) {String verifyKey = CacheConstants.CAPTCHA_CODE_KEY + StringUtils.nvl(uuid, "");//驗(yàn)證碼key值String captcha = redisCache.getCacheObject(verifyKey); //拿到緩存的數(shù)據(jù)redisCache.deleteObject(verifyKey);//刪除該緩存if (captcha == null) {//異步記錄登錄信息sys_logininforAsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire")));throw new CaptchaExpireException(); //拋出一個(gè)驗(yàn)證碼過期異常}if (!code.equalsIgnoreCase(captcha)) {//異步記錄登錄信息sys_logininforAsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.error")));throw new CaptchaException(); //拋出一個(gè)驗(yàn)證碼錯(cuò)誤的異常}}5.驗(yàn)證碼發(fā)送
發(fā)送用戶短信的方法,就不提供了,這里就是發(fā)送驗(yàn)證碼,并存起來。
@GetMapping("/appCaptcha")public AjaxResult getAppCode(Long deptId,String phone) throws Exception {//創(chuàng)建一個(gè)返回對(duì)象AjaxResult ajax = AjaxResult.success();// 保存驗(yàn)證碼信息String uuid = IdUtils.simpleUUID(); //生成一個(gè)uuidString verifyKey = CacheConstants.CAPTCHA_CODE_KEY + uuid;// 生成四位數(shù)驗(yàn)證碼String code = RandomUtil.getFourBitRandom();// 查詢短信參數(shù)信息ShortMessage shortMessage = shortMessageService.selectShortMessageByDeptId(deptId);// 通過阿里云短信發(fā)送短信boolean sent = ShortMessageUtils.sent(shortMessage, phone, code);//把驗(yàn)證碼答應(yīng)存入緩存,10分鐘的時(shí)間redisCache.setCacheObject(verifyKey, code, Constants.CODE_EXPIRATION, TimeUnit.MINUTES);//把信息封裝返回ajax.put("uuid", uuid);總結(jié)
- 上一篇: Patch2Pix(CVPR 2021)
- 下一篇: 【雷达成像】基于距离多普勒(RD)、CS