若依短信验证码登录
解決若依框架短信驗證碼登錄,并且不影響原有登錄
文章目錄
一、實現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 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);}@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);總結
- 上一篇: Patch2Pix(CVPR 2021)
- 下一篇: 【雷达成像】基于距离多普勒(RD)、CS