Browse Source

更新作者版本

master
zhouhaibin 3 months ago
parent
commit
4fecb777c8
  1. 2
      platform-boot-starter-demo/src/main/resources/application.yml
  2. 11
      platform-boot-starter/src/main/resources/application-platform.yml
  3. 5
      platform-common/src/main/java/tech/abc/platform/common/exception/CommonException.java
  4. 1
      platform-framework/src/main/java/tech/abc/platform/framework/config/properties/system/SystemProperties.java
  5. 4
      platform-framework/src/main/java/tech/abc/platform/framework/security/UserDetailsServiceImpl.java
  6. 6
      platform-system/pom.xml
  7. 5
      platform-system/src/main/java/tech/abc/platform/system/config/SystemConfig.java
  8. 53
      platform-system/src/main/java/tech/abc/platform/system/controller/UserController.java
  9. 18
      platform-system/src/main/java/tech/abc/platform/system/exception/UserExceptionEnum.java
  10. 45
      platform-system/src/main/java/tech/abc/platform/system/service/UserService.java
  11. 213
      platform-system/src/main/java/tech/abc/platform/system/service/impl/UserServiceImpl.java
  12. 46
      platform-system/src/main/java/tech/abc/platform/system/vo/RegisterUserVO.java

2
platform-boot-starter-demo/src/main/resources/application.yml

@ -1,5 +1,5 @@
spring:
profiles:
include: platform
include: platform,dev

11
platform-boot-starter/src/main/resources/application-platform.yml

@ -120,6 +120,7 @@ platform-config:
userInitPassword: 12345678
tokenSecret: wqliu
exportDataPageSize: 2
systemUrl: http://localhost:4000
notification:
serverPort: 9997
message:
@ -136,7 +137,7 @@ platform-config:
# 集成minio模式
# storeClass: tech.abc.platform.oss.service.impl.MinioStoreServiceImpl
# 本地磁盘需要给出路径,如c:/attachment/或/data;minio因使用桶作为逻辑存储,无根路径,需留空
basePath: d:/ce/
basePath: c:/attachment/
minio:
server: http://127.0.0.1:9000
accessKey: admin
@ -179,10 +180,10 @@ platform-config:
#工作流配置
camunda:
bpm:
# admin-user:
# id: admin
# password: admin
# firstName: Kermit
# admin-user:
# id: admin
# password: admin
# firstName: Kermit
database:
type: mysql
schema-update: true

5
platform-common/src/main/java/tech/abc/platform/common/exception/CommonException.java

@ -108,7 +108,10 @@ public enum CommonException implements ExceptionInterface {
*/
ENUM_TYPE_NOT_FOUNT("未找到对应的枚举类型:【{0}】"),
;
/**
* 无效的枚举值
*/
INVALID_ENUM("无效的枚举值:{0}");
private String message;

1
platform-framework/src/main/java/tech/abc/platform/framework/config/properties/system/SystemProperties.java

@ -31,5 +31,4 @@ public class SystemProperties {
*/
private String tokenSecret = "wqliu";
}

4
platform-framework/src/main/java/tech/abc/platform/framework/security/UserDetailsServiceImpl.java

@ -1,15 +1,19 @@
package tech.abc.platform.framework.security;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Component;
import tech.abc.platform.common.constant.TreeDefaultConstant;
import tech.abc.platform.common.entity.MyGrantedAuthority;
import tech.abc.platform.common.entity.MyUserDetails;
import tech.abc.platform.common.utils.CacheUtil;
import tech.abc.platform.system.entity.Organization;
import tech.abc.platform.system.entity.User;
import tech.abc.platform.system.enums.OrganizationTypeEnum;
import tech.abc.platform.system.enums.UserStatusEnum;
import tech.abc.platform.system.service.OrganizationService;
import tech.abc.platform.system.service.UserService;

6
platform-system/pom.xml

@ -38,6 +38,12 @@
<groupId>tech.abc</groupId>
<artifactId>platform-boot-starter-notification</artifactId>
</dependency>
<dependency>
<groupId>tech.abc</groupId>
<artifactId>platform-boot-starter-mail</artifactId>
</dependency>
</dependencies>

5
platform-system/src/main/java/tech/abc/platform/system/config/SystemConfig.java

@ -23,5 +23,10 @@ public class SystemConfig {
*/
private String userInitPassword = "654321";
/**
* 系统地址
*/
private String systemUrl = "http://localhost:4000";
}

53
platform-system/src/main/java/tech/abc/platform/system/controller/UserController.java

@ -11,6 +11,7 @@ import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import tech.abc.platform.common.annotation.AllowAll;
import tech.abc.platform.common.annotation.AllowAuthenticated;
import tech.abc.platform.common.annotation.SystemLog;
import tech.abc.platform.common.base.BaseController;
@ -26,6 +27,7 @@ import tech.abc.platform.system.entity.User;
import tech.abc.platform.system.service.GroupUserService;
import tech.abc.platform.system.service.OrganizationService;
import tech.abc.platform.system.service.UserService;
import tech.abc.platform.system.vo.RegisterUserVO;
import tech.abc.platform.system.vo.UserChangePasswordVO;
import tech.abc.platform.system.vo.UserVO;
@ -230,7 +232,7 @@ public class UserController extends BaseController {
@AllowAuthenticated
public ResponseEntity<Result> changePassword(@RequestBody UserChangePasswordVO vo) {
userService.changePassword(vo.getUserId(), vo.getOldPassword(), vo.getNewPassword());
userService.changeUserPassword(vo.getUserId(), vo.getOldPassword(), vo.getNewPassword());
return ResultUtil.success();
}
@ -349,6 +351,55 @@ public class UserController extends BaseController {
return ResultUtil.success(new ArrayList<UserVO>());
}
/**
* 注册
*/
@PostMapping("/register")
@SystemLog(value = "用户-注册")
@AllowAll
public ResponseEntity<Result> register(@Validated @RequestBody RegisterUserVO vo) {
User entity = new User();
mapperFacade.map(vo, entity);
userService.register(entity);
return ResultUtil.success();
}
/**
* 注册
*/
@PostMapping("/retrievePassword")
@SystemLog(value = "用户-找回密码")
@AllowAll
public ResponseEntity<Result> retrievePassword(String email) {
userService.retrievePassword(email);
return ResultUtil.success();
}
/**
* 根据授权码获取账号
*/
@GetMapping("/getAccoutByCode")
@SystemLog(value = "用户-根据授权码获取账号")
@AllowAll
public ResponseEntity<Result> getAccoutByCode(String code) {
String account = userService.getAccoutByCode(code);
return ResultUtil.success(account);
}
/**
* 用户自助重设密码
*/
@PutMapping("/selfResetPassword")
@SystemLog(value = "用户自助重设密码", logType = LogTypeEnum.AUDIT)
@AllowAll
public ResponseEntity<Result> selfResetPassword(String code, String password) {
userService.selfResetPassword(code, password);
return ResultUtil.success();
}
// endregion
// region 辅助操作
private UserVO convert2VO(User entity) {
UserVO vo = mapperFacade.map(entity, UserVO.class);

18
platform-system/src/main/java/tech/abc/platform/system/exception/UserExceptionEnum.java

@ -62,6 +62,24 @@ public enum UserExceptionEnum implements ExceptionInterface {
*/
ORGANIZATION_NAME_AND_CODE_CANOT_NULL("组织机构名称和组织机构编码不能同时为空"),
/**
* 账号与邮箱不匹配
*/
ACCOUNT_EMAIL_NOT_MATCH("账号与邮箱不匹配,请确认"),
/**
* 该邮箱未注册
*/
EMAIl_NOT_REGISTER("该邮箱未注册,请确认"),
/**
* 授权码已失效
*/
AUTHORIZATION_CODE_EXPIRED("授权码已失效,请重新获取"),
/**
* 账号不存在
*/
ACCOUNT_NOT_EXIST("账号不存在"),
;
private String message;

45
platform-system/src/main/java/tech/abc/platform/system/service/UserService.java

@ -22,7 +22,7 @@ public interface UserService extends BaseService<User> {
* @return 集合
*/
Map<String, String> getNameMap(List<String> idList);
/**
* 启用
*
@ -61,11 +61,11 @@ public interface UserService extends BaseService<User> {
/**
* 用户修改密码
*
* @param account 账号
* @param id 用户标识
* @param oldPassword 旧密码
* @param newPassword 新密码
*/
void changePassword(String account, String oldPassword, String newPassword);
void changeUserPassword(String id, String oldPassword, String newPassword);
/**
* 更新登录失败次数
@ -119,8 +119,47 @@ public interface UserService extends BaseService<User> {
/**
* 获取姓名
*
* @param id 用户标识
* @return {@link String} 姓名
*/
String getNameById(String id);
/**
* 注册用户
*
* @param entity
*/
void register(User entity);
/**
* 找回密码
*
* @param email 邮箱
*/
void retrievePassword(String email);
/**
* 根据授权码获取账号
*
* @param code 授权码
* @return {@link String} 账号
*/
String getAccoutByCode(String code);
/**
* 自助重设密码
*
* @param code 授权码
* @param password 新密码
*/
void selfResetPassword(String code, String password);
/**
* 根据账号获取用户标识
*
* @param account 账号
* @return {@link String} 用户标识
*/
String getIdByAccount(String account);
}

213
platform-system/src/main/java/tech/abc/platform/system/service/impl/UserServiceImpl.java

@ -9,19 +9,20 @@ import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import tech.abc.platform.common.annotation.SystemLog;
import tech.abc.platform.common.base.BaseServiceImpl;
import tech.abc.platform.common.enums.ExecuteResultEnum;
import tech.abc.platform.common.enums.LogTypeEnum;
import tech.abc.platform.common.enums.StatusEnum;
import tech.abc.platform.common.enums.YesOrNoEnum;
import tech.abc.platform.common.exception.CustomException;
import tech.abc.platform.common.utils.CacheUtil;
import tech.abc.platform.common.utils.EncryptUtil;
import tech.abc.platform.mail.service.MailService;
import tech.abc.platform.system.config.SystemConfig;
import tech.abc.platform.system.constant.SystemConstant;
import tech.abc.platform.system.entity.GroupUser;
import tech.abc.platform.system.entity.PermissionItem;
import tech.abc.platform.system.entity.User;
import tech.abc.platform.system.entity.UserPasswordChangeLog;
import tech.abc.platform.common.enums.ExecuteResultEnum;
import tech.abc.platform.system.enums.UserStatusEnum;
import tech.abc.platform.system.exception.PermissionItemExceptionEnum;
import tech.abc.platform.system.exception.UserExceptionEnum;
@ -31,9 +32,8 @@ import tech.abc.platform.system.utils.PasswordUtil;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.*;
import java.util.concurrent.TimeUnit;
/**
* 用户 服务实现类
@ -66,6 +66,9 @@ public class UserServiceImpl extends BaseServiceImpl<UserMapper, User> implement
@Autowired
private PermissionItemService permissionItemService;
@Autowired
private MailService mailService;
@Override
public User init() {
User entity = new User();
@ -212,36 +215,42 @@ public class UserServiceImpl extends BaseServiceImpl<UserMapper, User> implement
@Override
@Transactional(rollbackFor = Exception.class)
public void changePassword(String id, String oldPassword, String newPassword) {
// 检验账号以及旧密码,验证新密码强度
User user = checkAccountPassword(id, oldPassword, newPassword);
public void changeUserPassword(String id, String oldPassword, String newPassword) {
// 检验旧密码是否正确,以及新旧密码是否相同
checkAccountPassword(id, oldPassword, newPassword);
// 校验密码安全规则
checkSafePolicy(user, newPassword);
checkSafePolicy(id, newPassword);
// 修改密码
changePassword(id, newPassword);
}
private void changePassword(String id, String password) {
User user = query(id);
// 缓存原始密码
String originPassword = user.getPassword();
// 修改密码
// 设置密码加密
String encrtyPassword = EncryptUtil.bCryptPasswordEncode(newPassword);
String encrtyPassword = EncryptUtil.bCryptPasswordEncode(password);
user.setPassword(encrtyPassword);
// 将强制修改密码标识位设置为否
user.setForceChangePasswordFlag(YesOrNoEnum.NO.name());
// 修改
modify(user);
// 记录日志
UserPasswordChangeLog log = new UserPasswordChangeLog();
log.setAccount(user.getAccount());
log.setUserId(user.getId());
log.setChangeTime(LocalDateTime.now());
log.setOriginPassword(EncryptUtil.bCryptPasswordEncode(oldPassword));
log.setOriginPassword(originPassword);
userPasswordChangeLogService.add(log);
}
/**
* 校验账号账号以及旧密码校验
*/
public User checkAccountPassword(String id, String oldPassword, String newPassword) {
public void checkAccountPassword(String id, String oldPassword, String newPassword) {
// 获取用户
User entity = getEntity(id);
// 验证旧密码
if (!EncryptUtil.bCryptPasswordMatches(oldPassword, entity.getPassword())) {
// 更新累计错误次数
@ -254,15 +263,7 @@ public class UserServiceImpl extends BaseServiceImpl<UserMapper, User> implement
if (oldPassword.equals(newPassword)) {
throw new CustomException(UserExceptionEnum.PWD_OLD_NEW_SAME);
}
// 新密码复杂度验证:包括大写字母、小写字母、数字、特殊符号这4种类型中的3种
if (!PasswordUtil.isComplexPassword(newPassword)) {
throw new CustomException(UserExceptionEnum.PWD_CHANGE_NOT_STRONG);
}
// 验证新密码不能包含账号、电话号码或出生日期三者中任何一项
if (!checkPasswordSimple(newPassword, entity)) {
throw new CustomException(UserExceptionEnum.PWD_CHANGE_EASY);
}
return entity;
}
/**
@ -359,6 +360,125 @@ public class UserServiceImpl extends BaseServiceImpl<UserMapper, User> implement
return user.getName();
}
@Override
@Transactional(rollbackFor = Exception.class)
public void register(User entity) {
// 验证账号全局唯一
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.lambda().eq(User::getAccount, entity.getAccount());
long count = count(queryWrapper);
if (count > 0) {
throw new CustomException(UserExceptionEnum.ACCOUNT_EXIST);
}
// 验证密码基本要求
checkPasswordBasicRequire(entity.getPassword());
// 设置密码
entity.setPassword(EncryptUtil.bCryptPasswordEncode(entity.getPassword()));
// 强制修改密码状态位置为否
entity.setForceChangePasswordFlag(YesOrNoEnum.NO.toString());
// 状态初始化为正常
entity.setStatus(UserStatusEnum.NORMAL.toString());
// 设置性别
entity.setGender("MALE");
// 设置默认部门为 遇见 应用
entity.setOrganization("999");
// 调用父类保存
super.save(entity);
// 设置通用角色
List<String> userIdList = new ArrayList<>();
userIdList.add(entity.getId());
groupUserService.addUser("999", userIdList);
}
@Override
public void retrievePassword(String email) {
// 验证邮箱是否注册
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.lambda().eq(User::getEmail, email);
List<User> list = list(queryWrapper);
if (CollectionUtils.isEmpty(list)) {
throw new CustomException(UserExceptionEnum.EMAIl_NOT_REGISTER);
}
User user = list.get(0);
// 发送重设邮件
String account = user.getAccount();
sendResetPasswordEmail(email, account);
}
private void sendResetPasswordEmail(String email, String account) {
// 生成唯一性编码
String code = UUID.randomUUID().toString();
// 存入redis,24小时后失效
cacheUtil.set(code, account, 24, TimeUnit.HOURS);
// 生成内容
String systemUrl = systemConfig.getSystemUrl();
String content = "重设【遇见】应用密码:" + systemUrl + "/#/selfResetPassword?code=" + code;
// 使用线程异步发送邮件
Runnable runnable = new Runnable() {
@Override
public void run() {
mailService.sendHtmlMail(email, "重设【遇见】应用密码", content);
}
};
// noinspection AlibabaAvoidManuallyCreateThread
Thread thread = new Thread(runnable);
// 启动
thread.start();
}
@Override
public String getAccoutByCode(String code) {
Object object = cacheUtil.get(code);
if (object != null) {
return object.toString();
} else {
throw new CustomException(UserExceptionEnum.AUTHORIZATION_CODE_EXPIRED);
}
}
@Override
public void selfResetPassword(String code, String password) {
// 获取账号
String account = getAccoutByCode(code);
String id = getIdByAccount(account);
User user = query(id);
// 验证密码
checkSafePolicy(id, password);
// 修改密码
changePassword(id, password);
// 删除缓存授权码
cacheUtil.remove(code);
}
@Override
public String getIdByAccount(String account) {
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.lambda().eq(User::getAccount, account);
List<User> list = list(queryWrapper);
if (CollectionUtils.isEmpty(list)) {
throw new CustomException(UserExceptionEnum.ACCOUNT_NOT_EXIST);
}
User user = list.get(0);
return user.getId();
}
/**
* 安全认证校验
@ -367,23 +487,22 @@ public class UserServiceImpl extends BaseServiceImpl<UserMapper, User> implement
* @param password
* @return
*/
public void checkSafePolicy(User user, String password) {
// 密码长度
// 系统配置密码最小长度
Integer passwordLength = Integer.parseInt(paramService.getParamValue(SystemConstant.PASSWORD_LENGTH));
// 比较密码长度
if (password.length() < passwordLength) {
throw new CustomException(UserExceptionEnum.PWD_CHANGE_NEED_LENGTH);
public void checkSafePolicy(String id, String password) {
// 验证密码基本要求(长度及复杂度)
checkPasswordBasicRequire(password);
// 验证新密码不能包含账号、电话号码或出生日期三者中任何一项
if (!checkPasswordSimple(password, id)) {
throw new CustomException(UserExceptionEnum.PWD_CHANGE_EASY);
}
// n次以内不得设置相同的密码
// 系统配置密码最小长度
// 验证n次以内不得设置相同的密码
Integer passwordCount = Integer.parseInt(paramService.getParamValue(SystemConstant.PASSWORD_UPDATE_SAME_TIMES));
// 从密码修改日志中获取最后N次修改的密码
QueryWrapper<UserPasswordChangeLog> queryWrapper = new QueryWrapper<>();
queryWrapper.lambda().eq(UserPasswordChangeLog::getId, user.getId())
queryWrapper.lambda().eq(UserPasswordChangeLog::getUserId, id)
.orderByDesc(UserPasswordChangeLog::getChangeTime);
queryWrapper.last("limit 0," + passwordCount);
List<UserPasswordChangeLog> logList = userPasswordChangeLogService.list(queryWrapper);
for (UserPasswordChangeLog log : logList) {
if (EncryptUtil.bCryptPasswordMatches(password, log.getOriginPassword())) {
@ -393,16 +512,34 @@ public class UserServiceImpl extends BaseServiceImpl<UserMapper, User> implement
}
/**
* 验证密码基本要求长度及复杂度
*
* @param password 密码
*/
private void checkPasswordBasicRequire(String password) {
// 验证密码长度
Integer passwordLength = Integer.parseInt(paramService.getParamValue(SystemConstant.PASSWORD_LENGTH));
if (password.length() < passwordLength) {
throw new CustomException(UserExceptionEnum.PWD_CHANGE_NEED_LENGTH);
}
// 验证密码复杂度:包括大写字母、小写字母、数字、特殊符号这4种类型中的3种
if (!PasswordUtil.isComplexPassword(password)) {
throw new CustomException(UserExceptionEnum.PWD_CHANGE_NOT_STRONG);
}
}
/**
* 验证新密码不能包含账号电话号码或出生日期三者中任何一项
* 验证密码不能包含账号电话号码或出生日期三者中任何一项
*
* @param password
* @param user
* @param password 密码
* @param id 用户标识
* @return
*/
private boolean checkPasswordSimple(String password, User user) {
private boolean checkPasswordSimple(String password, String id) {
User user = query(id);
if (password.contains(user.getAccount())) {
return false;
}

46
platform-system/src/main/java/tech/abc/platform/system/vo/RegisterUserVO.java

@ -0,0 +1,46 @@
package tech.abc.platform.system.vo;
import lombok.Data;
import lombok.experimental.Accessors;
import javax.validation.constraints.NotBlank;
/**
* 注册用户 视图对象类
*
* @author wqliu
* @date 2023-05-24
*/
@Data
@Accessors(chain = true)
public class RegisterUserVO {
/**
* 姓名
*/
@NotBlank(message = "【姓名】不能为空")
private String name;
/**
* 账号
*/
@NotBlank(message = "【账号】不能为空")
private String account;
/**
* 密码
*/
private String password;
/**
* 邮箱
*/
@NotBlank(message = "【邮箱】不能为空")
private String email;
}
Loading…
Cancel
Save