手机号认证

This commit is contained in:
D 2024-04-16 14:01:24 +08:00
parent 62c9824426
commit 4c085cff34
7 changed files with 309 additions and 13 deletions

View File

@ -0,0 +1,37 @@
package com.ruoyi.oauth.common.enums;
public enum OauthVerificationUse {
LOGIN("登录", "login"),
REGISTER("注册", "register"),
DISABLE("禁用", "disable"),
RESET_PASSWORD("重置密码", "reset_password"),
RESET_PHONE("重置手机号", "reset_phone"),
Other("其他","other");
private String name;
private String value;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
private OauthVerificationUse(String name, String value) {
this.name = name;
this.value = value;
}
}

View File

@ -0,0 +1,15 @@
package com.ruoyi.oauth.common.service;
import com.ruoyi.oauth.common.enums.OauthVerificationUse;
/**
* code认证方式接口
*
* @author zlh
* @date 2024-04-16
*/
public interface OauthVerificationCodeService {
public boolean sendCode(String o, String code,OauthVerificationUse use) throws Exception;
public String checkCode(String o, String code,OauthVerificationUse use) throws Exception;
}

View File

@ -3,6 +3,12 @@ package com.ruoyi.oauth.phone.constant;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
/**
* 手机号认证数据
*
* @author Dftre
* @date 2024-04-16
*/
@Component @Component
public class DySmsConstant { public class DySmsConstant {
@Value("${oauth.phone.dysms.appId}") @Value("${oauth.phone.dysms.appId}")

View File

@ -1,24 +1,153 @@
package com.ruoyi.oauth.phone.controller; package com.ruoyi.oauth.phone.controller;
import java.util.Random;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import com.ruoyi.common.annotation.Anonymous; import com.ruoyi.common.annotation.Anonymous;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.domain.model.LoginBody;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.oauth.common.enums.OauthVerificationUse;
import com.ruoyi.oauth.phone.service.DySmsService; import com.ruoyi.oauth.phone.service.DySmsService;
import com.ruoyi.system.service.ISysUserService;
/**
* 手机号认证Controller
*
* @author zlh
* @date 2024-04-16
*/
@RestController @RestController
@Anonymous
@RequestMapping("/oauth/phone") @RequestMapping("/oauth/phone")
public class DySmsController { public class DySmsController extends BaseController {
@Autowired @Autowired
public DySmsService dySmsService; public DySmsService dySmsService;
@PostMapping("/login")
public String postMethodName() { @Autowired
dySmsService.doLogin("17854126030"); private ISysUserService userService;
return null;
@Anonymous
@PostMapping("/sendcode/{mode}") // 发送验证码
public AjaxResult sendcode(@RequestBody LoginBody loginBody, @PathVariable(value = "mode") String mode)
throws Exception {
try {
OauthVerificationUse oauthVerificationUse = null;
switch (mode) {
case "login":
oauthVerificationUse = OauthVerificationUse.LOGIN;
break;
case "register":
oauthVerificationUse = OauthVerificationUse.REGISTER;
break;
case "disable":
oauthVerificationUse = OauthVerificationUse.DISABLE;
break;
case "resetpassword":
oauthVerificationUse = OauthVerificationUse.RESET_PASSWORD;
break;
case "resetphone":
oauthVerificationUse = OauthVerificationUse.RESET_PHONE;
break;
default:
oauthVerificationUse = OauthVerificationUse.Other;
}
String code = generateRandomString(6);
dySmsService.sendCode(loginBody.getUsername(), code, oauthVerificationUse);
return AjaxResult.success("发送验证码成功");
} catch (Exception e) {
return AjaxResult.error("发送验证码失败,原因: " + e.getMessage());
}
}
public static String generateRandomString(int n) {
String characters = "0123456789"; // ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
StringBuilder result = new StringBuilder();
Random random = new Random();
for (int i = 0; i < n; i++) {
int index = random.nextInt(characters.length());
result.append(characters.charAt(index));
}
return result.toString();
}
@Anonymous
@PostMapping("/login") // 登录
public AjaxResult postMethodName(@RequestBody LoginBody loginBody) throws Exception {
if (dySmsService.checkCode(loginBody.getUsername(), loginBody.getCode(),
OauthVerificationUse.LOGIN) == "false") {
return AjaxResult.error("登录失败");
} else {
return AjaxResult.success("登录成功");
}
}
@Anonymous
@PostMapping("/register") // 注册
public AjaxResult postenroll(@RequestBody LoginBody loginBody) throws Exception {
try {
dySmsService.checkCode(loginBody.getUsername(), loginBody.getCode(), OauthVerificationUse.REGISTER);
// 验证通过执行注册逻辑
SysUser user = new SysUser();
user.setUserName(loginBody.getUsername());
user.setNickName(loginBody.getUsername());
user.setPassword(SecurityUtils.encryptPassword(loginBody.getPassword()));
user.setPhonenumber(loginBody.getUsername());
userService.insertUser(user);
return AjaxResult.success("注册成功");
} catch (Exception e) {
// return "注册失败,原因: " + e.getMessage();
return AjaxResult.error("注册失败");
}
}
@PostMapping("/disable") // 注销
public AjaxResult postlogout(@RequestBody LoginBody loginBody) throws Exception {
try {
dySmsService.checkCode(getUsername(), loginBody.getCode(), OauthVerificationUse.DISABLE);
// 验证通过执行注销逻辑
SysUser sysUser = userService.selectUserByPhone(loginBody.getUsername());
userService.deleteUserById(sysUser.getUserId());
return AjaxResult.success("注销成功");
} catch (Exception e) {
return AjaxResult.error("注销失败,原因: " + e.getMessage());
}
}
@Anonymous
@PostMapping("/resetpassword") // 重置密码
public AjaxResult postpassword(@RequestBody LoginBody loginBody) throws Exception {
try {
dySmsService.checkCode(loginBody.getUsername(), loginBody.getCode(), OauthVerificationUse.RESET_PASSWORD);
// 验证通过执行重置密码逻辑
SysUser sysUser = userService.selectUserByPhone(loginBody.getUsername());
sysUser.setPassword(SecurityUtils.encryptPassword(loginBody.getPassword()));
userService.updateUser(sysUser);
return AjaxResult.success("重置密码成功");
} catch (Exception e) {
return AjaxResult.error("重置密码失败,原因: " + e.getMessage());
}
}
@PostMapping("/resetphone") // 重置手机号
public AjaxResult postphone(@RequestBody LoginBody loginBody) throws Exception {
try {
dySmsService.checkCode(loginBody.getUsername(), loginBody.getCode(), OauthVerificationUse.RESET_PHONE);
// 验证通过执行重置密码逻辑
SysUser sysUser = userService.selectUserByUserName(getUsername());
sysUser.setPhonenumber(loginBody.getUsername());
userService.updateUser(sysUser);
return AjaxResult.success("重置手机号成功");
} catch (Exception e) {
return AjaxResult.error("重置手机号失败,原因: " + e.getMessage());
}
} }
} }

View File

@ -2,6 +2,12 @@ package com.ruoyi.oauth.phone.enums;
import com.ruoyi.common.utils.StringUtils; import com.ruoyi.common.utils.StringUtils;
/**
* 手机号认证短信模板
*
* @author Dftre
* @date 2024-04-16
*/
public enum DySmsTemplate { public enum DySmsTemplate {
/** 登录短信模板编码 */ /** 登录短信模板编码 */
LOGIN_TEMPLATE_CODE("SMS_175435174", "Ruoyi", "code"), LOGIN_TEMPLATE_CODE("SMS_175435174", "Ruoyi", "code"),

View File

@ -1,5 +1,21 @@
package com.ruoyi.oauth.phone.service; package com.ruoyi.oauth.phone.service;
import com.ruoyi.oauth.common.enums.OauthVerificationUse;
/**
* 手机号认证Servcie
*
* @author zlh
* @date 2024-04-16
*/
public interface DySmsService { public interface DySmsService {
public String doLogin(String phone); public String doLogin(String phone);
public boolean sendCode(String phone, String code, OauthVerificationUse use) throws Exception;
public String checkCode(String phone, String code, OauthVerificationUse use) throws Exception;
// public String doenroll(String phone,String username, String password);
} }

View File

@ -3,6 +3,8 @@ package com.ruoyi.oauth.phone.service.Impl;
import java.util.Random; import java.util.Random;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@ -13,13 +15,21 @@ import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.exception.ServiceException; import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.framework.web.service.TokenService; import com.ruoyi.framework.web.service.TokenService;
import com.ruoyi.framework.web.service.UserDetailsServiceImpl; import com.ruoyi.framework.web.service.UserDetailsServiceImpl;
import com.ruoyi.oauth.common.enums.OauthVerificationUse;
import com.ruoyi.oauth.common.service.OauthVerificationCodeService;
import com.ruoyi.oauth.phone.enums.DySmsTemplate; import com.ruoyi.oauth.phone.enums.DySmsTemplate;
import com.ruoyi.oauth.phone.service.DySmsService; import com.ruoyi.oauth.phone.service.DySmsService;
import com.ruoyi.oauth.phone.utils.DySmsUtil; import com.ruoyi.oauth.phone.utils.DySmsUtil;
import com.ruoyi.system.service.ISysUserService; import com.ruoyi.system.service.ISysUserService;
/**
* 手机号认证Servcie
*
* @author zlh
* @date 2024-04-16
*/
@Service @Service
public class DySmsServiceImpl implements DySmsService { public class DySmsServiceImpl implements DySmsService, OauthVerificationCodeService {
@Autowired @Autowired
private DySmsUtil dySmsUtil; private DySmsUtil dySmsUtil;
@ -32,8 +42,85 @@ public class DySmsServiceImpl implements DySmsService {
@Autowired @Autowired
private TokenService tokenService; private TokenService tokenService;
private static final Logger log = LoggerFactory.getLogger(DySmsServiceImpl.class);
public boolean beforeSendCode(String phone, OauthVerificationUse use) throws Exception {//1.查验手机号是否存在分辨登录和删除用户以及注册用户
boolean havePhoneFlag= userService.selectUserByPhone(phone) != null;
if((use.equals(OauthVerificationUse.LOGIN ) || use.equals(OauthVerificationUse.DISABLE )||use.equals(OauthVerificationUse.RESET_PASSWORD) )&& !havePhoneFlag){
throw new ServiceException("该手机号未绑定用户");
}else if((use.equals(OauthVerificationUse.REGISTER ) ||use.equals(OauthVerificationUse.RESET_PHONE))&& havePhoneFlag){
throw new ServiceException("该手机号已绑定用户");
}
return true;
}
@Override
public boolean sendCode(String phone, String code, OauthVerificationUse use) throws Exception {//1.查验手机号是否存在分辨登录和删除用户以及注册用户
//限制短信一分钟只能发送一次短信
String cacheKey = "phone_codes_" + use.getValue() + "_" + phone;
if(redisCache.hasKey(cacheKey)){
throw new ServiceException("请在1分钟后再发送短信");
}
try {
JSONObject templateParams = new JSONObject();
templateParams.put("code", code);
dySmsUtil.sendSms(DySmsTemplate.Test_TEMPLATE_CODE, templateParams, phone);
redisCache.setCacheObject("phone_codes_" + use.getValue() + "_" + phone, code, 1, TimeUnit.MINUTES);
log.info("发送手机验证码成功:{ phone: " + phone + " code:" + code + "}");
return true;
} catch (Exception e) {
log.error("发送手机验证码异常:" + phone);
throw e;
}
}
@Override
public String checkCode(String phone, String code, OauthVerificationUse use) throws Exception{
String cacheKey = "phone_codes_" + use.getValue() + "_" + phone;
String cachedCode = redisCache.getCacheObject(cacheKey); // 从缓存中获取验证码
boolean havePhoneFlag= userService.selectUserByPhone(phone) != null;
if(use.equals(OauthVerificationUse.LOGIN ) && havePhoneFlag){//登录校验
if (code.equals(cachedCode)) {
SysUser sysUser = userService.selectUserByPhone(phone);
LoginUser loginUser = (LoginUser) userDetailsServiceImpl.createLoginUser(sysUser);
return tokenService.createToken(loginUser);
// return true;
} else {
throw new ServiceException("验证码错误");
}
}else if(use.equals(OauthVerificationUse.REGISTER )&& !havePhoneFlag){//注册校验
if (code.equals(cachedCode)) {
return Boolean.toString(true);
} else {
throw new ServiceException("验证码错误");
}
}else if(use.equals(OauthVerificationUse.DISABLE )&& havePhoneFlag){//注销校验
if (code.equals(cachedCode)) {
return Boolean.toString(true);
} else {
throw new ServiceException("验证码错误");
}
}else if(use.equals(OauthVerificationUse.RESET_PASSWORD )&& havePhoneFlag){//重置密码校验
if (code.equals(cachedCode)) {
return Boolean.toString(true);
} else {
throw new ServiceException("验证码错误");
}
}else if(use.equals(OauthVerificationUse.RESET_PHONE )&& !havePhoneFlag){//重置账号校验
if (code.equals(cachedCode)) {
return Boolean.toString(true);
} else {
throw new ServiceException("验证码错误");
}
}
return Boolean.toString(false);
}
public static String generateRandomString(int n) { public static String generateRandomString(int n) {
String characters = "0123456789"; //ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz String characters = "0123456789"; // ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
StringBuilder result = new StringBuilder(); StringBuilder result = new StringBuilder();
Random random = new Random(); Random random = new Random();
@ -48,7 +135,7 @@ public class DySmsServiceImpl implements DySmsService {
@Override @Override
public String doLogin(String phone) { public String doLogin(String phone) {
String verify = redisCache.getCacheObject("phone_codes_login" + phone); String verify = redisCache.getCacheObject("phone_codes_login" + phone);
if(verify != null){ if (verify != null) {
throw new ServiceException("该手机号验证码未过期"); throw new ServiceException("该手机号验证码未过期");
} }
String code = generateRandomString(6); String code = generateRandomString(6);
@ -82,9 +169,9 @@ public class DySmsServiceImpl implements DySmsService {
String code = generateRandomString(6); String code = generateRandomString(6);
redisCache.setCacheObject("phone_codes_register" + phone, code, 1, TimeUnit.MINUTES); redisCache.setCacheObject("phone_codes_register" + phone, code, 1, TimeUnit.MINUTES);
String verify = redisCache.getCacheObject("phone_codes_register" + phone); String verify = redisCache.getCacheObject("phone_codes_register" + phone);
if(verify != null){ if (verify != null) {
throw new ServiceException("该手机号验证码未过期"); throw new ServiceException("该手机号验证码未过期");
}else{ } else {
try { try {
dySmsUtil.sendSms(null, null, phone); dySmsUtil.sendSms(null, null, phone);
redisCache.setCacheObject("phone_codes_register" + phone, code, 1, TimeUnit.MINUTES); redisCache.setCacheObject("phone_codes_register" + phone, code, 1, TimeUnit.MINUTES);