Browse Source

1.兽医端PC登录是查询用户设计的表顺序问题

2.兽医PC端注册功能,注册时默认增加未审核角色
3.兽医PC端注册强密码校验
master
ma-zhongxu 1 month ago
parent
commit
d72081d2a4
  1. 26
      chenhai-admin/src/main/java/com/chenhai/web/controller/auth/MultiAuthController.java
  2. 5
      chenhai-common/src/main/java/com/chenhai/common/constant/Constants.java
  3. 58
      chenhai-common/src/main/java/com/chenhai/common/core/domain/model/VetRegisterBody.java
  4. 29
      chenhai-framework/src/main/java/com/chenhai/framework/security/provider/PhoneAuthenticationProvider.java
  5. 151
      chenhai-framework/src/main/java/com/chenhai/framework/web/service/SysLoginService.java

26
chenhai-admin/src/main/java/com/chenhai/web/controller/auth/MultiAuthController.java

@ -5,7 +5,6 @@ import com.chenhai.common.core.domain.AjaxResult;
import com.chenhai.common.core.domain.model.*; import com.chenhai.common.core.domain.model.*;
import com.chenhai.framework.web.service.SysLoginService; import com.chenhai.framework.web.service.SysLoginService;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
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.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
@ -83,4 +82,29 @@ public class MultiAuthController {
return AjaxResult.error(e.getMessage()); return AjaxResult.error(e.getMessage());
} }
} }
/**
* 牧户PC端注册
*/
@PostMapping("/vet/register")
public AjaxResult vetRegister(@Valid @RequestBody VetRegisterBody registerBody) {
try {
// 验证确认密码
if (!registerBody.getPassword().equals(registerBody.getConfirmPassword())) {
return AjaxResult.error("两次输入的密码不一致");
}
// 调用注册服务
String token = loginService.vetRegister(
registerBody.getPhone(),
registerBody.getPassword(),
registerBody.getClientType()
);
return AjaxResult.success("注册成功").put(Constants.TOKEN, token);
} catch (Exception e) {
return AjaxResult.error(e.getMessage());
}
}
} }

5
chenhai-common/src/main/java/com/chenhai/common/constant/Constants.java

@ -170,4 +170,9 @@ public class Constants
*/ */
public static final String[] JOB_ERROR_STR = { "java.net.URL", "javax.naming.InitialContext", "org.yaml.snakeyaml", public static final String[] JOB_ERROR_STR = { "java.net.URL", "javax.naming.InitialContext", "org.yaml.snakeyaml",
"org.springframework", "org.apache", "com.chenhai.common.utils.file", "com.chenhai.common.config", "com.chenhai.generator" }; "org.springframework", "org.apache", "com.chenhai.common.utils.file", "com.chenhai.common.config", "com.chenhai.generator" };
/**
* 密码必须包含大写小写数字和特殊字符且长度是8位以上
*/
public static final String PWD_REGEX = "^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)(?=.*[!@#$%^&*()=_+;':,.?]).{8,20}$";
} }

58
chenhai-common/src/main/java/com/chenhai/common/core/domain/model/VetRegisterBody.java

@ -0,0 +1,58 @@
package com.chenhai.common.core.domain.model;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Pattern;
import jakarta.validation.constraints.Size;
/**
* 兽医PC端注册请求
*/
public class VetRegisterBody {
@NotBlank(message = "手机号不能为空")
@Pattern(regexp = "^1[3-9]\\d{9}$", message = "手机号格式不正确")
private String phone;
@NotBlank(message = "密码不能为空")
@Size(min = 6, max = 20, message = "密码长度6-20位")
private String password;
@NotBlank(message = "确认密码不能为空")
private String confirmPassword;
// 客户端类型固定为 vet-pc
private String clientType = "vet-pc";
// getters and setters
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getConfirmPassword() {
return confirmPassword;
}
public void setConfirmPassword(String confirmPassword) {
this.confirmPassword = confirmPassword;
}
public String getClientType() {
return clientType;
}
public void setClientType(String clientType) {
this.clientType = clientType;
}
}

29
chenhai-framework/src/main/java/com/chenhai/framework/security/provider/PhoneAuthenticationProvider.java

@ -40,23 +40,32 @@ public class PhoneAuthenticationProvider implements AuthenticationProvider {
@Override @Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException { public Authentication authenticate(Authentication authentication) throws AuthenticationException {
PhoneAuthenticationToken authToken = (PhoneAuthenticationToken) authentication; PhoneAuthenticationToken authToken = (PhoneAuthenticationToken) authentication;
String phone = authToken.getPhone(); String phone = authToken.getPhone();
String password = authToken.getPassword(); String password = authToken.getPassword();
String clientType = authToken.getClientType(); String clientType = authToken.getClientType();
// 1. 验证参数 // 1. 验证参数
if (phone == null || password == null) { if (phone == null || password == null) {
throw new BadCredentialsException("手机号或密码不能为空"); throw new BadCredentialsException("手机号或密码不能为空");
} }
// 2. 根据手机号查找用户
SysUser user = userAuthService.findUserByAuth("phone", phone);
// 2. 根据手机号查找用户扩展查询逻辑
SysUser user = null;
// 扩展认证方式两步查询
// 第一步先查 user_auth 小程序注册的用户
user = userAuthService.findUserByAuth("phone", phone);
// 第二步如果没找到再查 sys_user 管理端创建的用户
if (user == null) {
user = userService.selectUserByPhone(phone);
}
if (user == null) { if (user == null) {
throw new BadCredentialsException("手机号未注册"); throw new BadCredentialsException("手机号未注册");
} }
// 3. 验证用户状态 // 3. 验证用户状态
if ("1".equals(user.getStatus())) { if ("1".equals(user.getStatus())) {
throw new ServiceException(MessageUtils.message("user.blocked")); throw new ServiceException(MessageUtils.message("user.blocked"));
@ -64,13 +73,13 @@ public class PhoneAuthenticationProvider implements AuthenticationProvider {
if ("2".equals(user.getDelFlag())) { if ("2".equals(user.getDelFlag())) {
throw new ServiceException(MessageUtils.message("user.password.delete")); throw new ServiceException(MessageUtils.message("user.password.delete"));
} }
// 4. 验证密码 // 4. 验证密码
if (!passwordEncoder.matches(password, user.getPassword())) { if (!passwordEncoder.matches(password, user.getPassword())) {
// 密码错误计数逻辑复用原有的 // 密码错误计数逻辑复用原有的
throw new BadCredentialsException("密码错误"); throw new BadCredentialsException("密码错误");
} }
// 5. 创建LoginUser // 5. 创建LoginUser
LoginUser loginUser = new LoginUser( LoginUser loginUser = new LoginUser(
user.getUserId(), user.getUserId(),
@ -79,7 +88,7 @@ public class PhoneAuthenticationProvider implements AuthenticationProvider {
permissionService.getMenuPermission(user), permissionService.getMenuPermission(user),
clientType clientType
); );
return new PhoneAuthenticationToken(loginUser, loginUser.getAuthorities()); return new PhoneAuthenticationToken(loginUser, loginUser.getAuthorities());
} }

151
chenhai-framework/src/main/java/com/chenhai/framework/web/service/SysLoginService.java

@ -1,6 +1,8 @@
package com.chenhai.framework.web.service; package com.chenhai.framework.web.service;
import com.chenhai.common.utils.*;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException; import org.springframework.security.authentication.BadCredentialsException;
@ -19,9 +21,6 @@ import com.chenhai.common.exception.user.CaptchaException;
import com.chenhai.common.exception.user.CaptchaExpireException; import com.chenhai.common.exception.user.CaptchaExpireException;
import com.chenhai.common.exception.user.UserNotExistsException; import com.chenhai.common.exception.user.UserNotExistsException;
import com.chenhai.common.exception.user.UserPasswordNotMatchException; import com.chenhai.common.exception.user.UserPasswordNotMatchException;
import com.chenhai.common.utils.DateUtils;
import com.chenhai.common.utils.MessageUtils;
import com.chenhai.common.utils.StringUtils;
import com.chenhai.common.utils.ip.IpUtils; import com.chenhai.common.utils.ip.IpUtils;
import com.chenhai.framework.manager.AsyncManager; import com.chenhai.framework.manager.AsyncManager;
import com.chenhai.framework.manager.factory.AsyncFactory; import com.chenhai.framework.manager.factory.AsyncFactory;
@ -31,7 +30,6 @@ import com.chenhai.framework.security.context.AuthenticationContextHolder;
import com.alibaba.fastjson2.JSONObject; import com.alibaba.fastjson2.JSONObject;
import com.chenhai.common.core.domain.entity.SysUser; import com.chenhai.common.core.domain.entity.SysUser;
import com.chenhai.common.core.domain.model.*; import com.chenhai.common.core.domain.model.*;
import com.chenhai.common.utils.WechatDecryptUtil;
import com.chenhai.framework.security.exception.WechatNeedBindException; import com.chenhai.framework.security.exception.WechatNeedBindException;
import com.chenhai.framework.security.token.PhoneAuthenticationToken; import com.chenhai.framework.security.token.PhoneAuthenticationToken;
import com.chenhai.framework.security.token.WechatAuthenticationToken; import com.chenhai.framework.security.token.WechatAuthenticationToken;
@ -50,6 +48,7 @@ import java.util.Map;
* *
* @author ruoyi * @author ruoyi
*/ */
@Slf4j
@Component @Component
public class SysLoginService public class SysLoginService
{ {
@ -410,4 +409,148 @@ public class SysLoginService
// ==================================================================== // ====================================================================
// =================== 多端登录方法结束 =============================== // =================== 多端登录方法结束 ===============================
// ==================================================================== // ====================================================================
// ====================================================================
// =================== 以下是牧户PC端注册方法 ========================
// ====================================================================
/**
* 牧户PC端注册
*
* @param phone 手机号
* @param password 密码
* @param clientType 客户端类型
* @return token
*/
@Transactional
public String vetRegister(String phone, String password, String clientType) {
try {
// 1. 验证手机号格式
if (!isValidPhone(phone)) {
throw new ServiceException("手机号格式不正确");
}
// 2. 验证密码强度
validatePassword(password);
// 3. 检查手机号是否已注册
checkPhoneRegistered(phone);
// 4. 创建牧户用户
SysUser user = createVetUser(phone, password, clientType);
// 5. 创建登录用户
LoginUser loginUser = new LoginUser(
user.getUserId(),
user.getDeptId(),
user,
permissionService.getMenuPermission(user),
clientType
);
// 6. 记录登录信息
recordLoginInfo(loginUser.getUserId());
// 7. 生成token
return tokenService.createToken(loginUser);
} catch (Exception e) {
throw new ServiceException("注册失败: " + e.getMessage());
}
}
/**
* 验证手机号格式
*/
private boolean isValidPhone(String phone) {
String regex = "^1[3-9]\\d{9}$";
return phone != null && phone.matches(regex);
}
/**
* 验证密码强度
*/
private void validatePassword(String password) {
if (password == null || password.length() < 6 || password.length() > 20) {
throw new ServiceException("密码长度需6-20位");
}
if (StringUtils.isBlank(password)) {
throw new ServiceException("密码不能为空");
}
if (!password.matches(Constants.PWD_REGEX)) {
throw new ServiceException("长度在 8 到 20 个字符且包含大小写字母、数字以及特殊符号");
}
}
/**
* 检查手机号是否已注册
*/
private void checkPhoneRegistered(String phone) {
// 检查 sys_user
SysUser existingUser = userService.selectUserByPhone(phone);
if (existingUser != null) {
// 检查是否是牧户
if ("02".equals(existingUser.getUserType())) {
throw new ServiceException("该手机号已注册为兽医用户");
} else {
throw new ServiceException("该手机号已注册为其他类型用户");
}
}
// 可选检查 user_auth
SysUser authUser = userAuthService.findUserByAuth("phone", phone);
if (authUser != null) {
throw new ServiceException("该手机号已注册");
}
}
/**
* 创建牧户用户
*/
private SysUser createVetUser(String phone, String password, String clientType) {
SysUser user = new SysUser();
// 生成用户名muhu_ + 手机后4位 + 4位随机数
String phoneSuffix = phone.length() > 4 ? phone.substring(phone.length() - 4) : phone;
String randomSuffix = String.format("%04d", (int)(Math.random() * 10000));
String username = "vet_" + phoneSuffix + "_" + randomSuffix;
user.setUserName(username);
// 设置昵称牧户 + 手机后4位
user.setNickName("用户" + phoneSuffix);
user.setUserType("01"); // 牧户
user.setEmail("");
user.setPhonenumber(phone);
user.setSex("0"); // 未知性别
user.setAvatar(""); // 默认头像
// 加密密码
user.setPassword(com.chenhai.common.utils.SecurityUtils.encryptPassword(password));
user.setStatus("0"); // 正常状态
user.setDelFlag("0");
user.setCreateTime(new Date());
// 这里在最初PC端注册因为兽医用户涉及审核因此先加入角色兽医未审核角色
Long[] roleIds = {6L}; // 兽医未审核角色ID
user.setRoleIds(roleIds);
// 插入用户
userService.insertUser(user);
// 重新查询获取完整用户信息
SysUser savedUser = userService.selectUserByUserName(username);
// 可选创建手机号认证记录
try {
userAuthService.bindAuth(savedUser.getUserId(), "phone", phone, null);
} catch (Exception e) {
log.warn("创建用户认证记录失败: userId={}, phone={}", savedUser.getUserId(), phone);
}
return savedUser;
}
} }
Loading…
Cancel
Save