添加重置密码功能

This commit is contained in:
2023-11-23 22:30:39 +08:00
parent 7964c79a0b
commit 333a1b4a37
12 changed files with 452 additions and 0 deletions

View File

@@ -15,4 +15,7 @@ public class Constants {
public static String SYSCONFIG_ENABLE_CAPTCHA = "enable_captcha";
public static String SYSCONFIG_SESSION_TIMEOUT = "session_timeout";
public static String SYSCONFIG_ACCOUNT_MAX_ONLINE = "account_max_online";
public static String SYSCONFIG_RESETPWD_ENABLE = "resetpwd_enable";
public static String SYSCONFIG_RESETPWD_TIMEOUT = "resetpwd_timeout";
public static String SYSCONFIG_RESETPWD_MAX_FAIL_COUNT = "resetpwd_max_fail_count";
}

View File

@@ -0,0 +1,64 @@
package cn.lihongjie.coal.resetPwd.controller;
import cn.lihongjie.coal.annotation.SysLog;
import cn.lihongjie.coal.base.dto.CommonQuery;
import cn.lihongjie.coal.base.dto.IdRequest;
import cn.lihongjie.coal.resetPwd.dto.ConfirmResetPasswordDto;
import cn.lihongjie.coal.resetPwd.dto.CreateResetPwdDto;
import cn.lihongjie.coal.resetPwd.dto.ResetPwdDto;
import cn.lihongjie.coal.resetPwd.dto.UpdateResetPwdDto;
import cn.lihongjie.coal.resetPwd.service.ResetPwdService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
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.RestController;
@RestController
@RequestMapping("/resetPwd")
@SysLog(module = "重置密码")
@Slf4j
public class ResetPwdController {
@Autowired private ResetPwdService service;
@PostMapping("/create")
public ResetPwdDto create(@RequestBody CreateResetPwdDto request) {
return this.service.create(request);
}
@PostMapping("/update")
public ResetPwdDto update(@RequestBody UpdateResetPwdDto request) {
return this.service.update(request);
}
@PostMapping("/delete")
public Object delete(@RequestBody IdRequest request) {
this.service.delete(request);
return true;
}
@PostMapping("/getById")
public ResetPwdDto getById(@RequestBody IdRequest request) {
return this.service.getById(request.getId());
}
@PostMapping("/list")
public Page<ResetPwdDto> list(@RequestBody CommonQuery request) {
return this.service.list(request);
}
@PostMapping("/startReset")
public String startReset(@RequestBody CreateResetPwdDto request) {
return this.service.startReset(request);
}
@PostMapping("/confirmReset")
public Object confirmReset(@RequestBody ConfirmResetPasswordDto request) {
this.service.confirmReset(request);
return null;
}
}

View File

@@ -0,0 +1,17 @@
package cn.lihongjie.coal.resetPwd.dto;
import lombok.Data;
import java.util.*;
@Data
public class ConfirmResetPasswordDto extends CreateResetPwdDto{
private String id;
private String code;
private String password;
}

View File

@@ -0,0 +1,23 @@
package cn.lihongjie.coal.resetPwd.dto;
import cn.lihongjie.coal.base.dto.OrgCommonDto;
import lombok.Data;
import org.hibernate.annotations.Comment;
@Data
public class CreateResetPwdDto extends OrgCommonDto {
private String userName;
@Comment("手机号")
private String phone;
@Comment("邮箱")
private String email;
}

View File

@@ -0,0 +1,38 @@
package cn.lihongjie.coal.resetPwd.dto;
import cn.lihongjie.coal.base.dto.OrgCommonDto;
import cn.lihongjie.coal.user.dto.UserDto;
import lombok.Data;
import org.hibernate.annotations.Comment;
import java.time.LocalDateTime;
@Data
public class ResetPwdDto extends OrgCommonDto {
private UserDto user;
@Comment("手机号")
private String phone;
@Comment("邮箱")
private String email;
@Comment("验证码")
private String code;
@Comment("最大失败次数, 超过之后需要重新获取验证码")
private Integer maxFailCount;
@Comment("失败次数")
private Integer failCount;
@Comment("过期时间")
private LocalDateTime expireTime;
}

View File

@@ -0,0 +1,9 @@
package cn.lihongjie.coal.resetPwd.dto;
import cn.lihongjie.coal.base.dto.OrgCommonDto;
import lombok.Data;
@Data
public class UpdateResetPwdDto extends OrgCommonDto {
}

View File

@@ -0,0 +1,49 @@
package cn.lihongjie.coal.resetPwd.entity;
import cn.lihongjie.coal.base.entity.OrgCommonEntity;
import cn.lihongjie.coal.user.entity.UserEntity;
import jakarta.persistence.Entity;
import jakarta.persistence.ManyToOne;
import lombok.Data;
import org.hibernate.annotations.Comment;
import java.time.LocalDateTime;
@Data
@Entity
public class ResetPwdEntity extends OrgCommonEntity {
@ManyToOne
private UserEntity user;
@Comment("手机号")
private String phone;
@Comment("邮箱")
private String email;
@Comment("验证码")
private String code;
@Comment("最大失败次数, 超过之后需要重新获取验证码")
private Integer maxFailCount;
@Comment("失败次数")
private Integer failCount;
@Comment("过期时间")
private LocalDateTime expireTime;
}

View File

@@ -0,0 +1,19 @@
package cn.lihongjie.coal.resetPwd.mapper;
import cn.lihongjie.coal.base.mapper.BaseMapper;
import cn.lihongjie.coal.base.mapper.CommonMapper;
import cn.lihongjie.coal.resetPwd.dto.CreateResetPwdDto;
import cn.lihongjie.coal.resetPwd.dto.ResetPwdDto;
import cn.lihongjie.coal.resetPwd.dto.UpdateResetPwdDto;
import cn.lihongjie.coal.resetPwd.entity.ResetPwdEntity;
import org.mapstruct.Mapper;
import org.mapstruct.control.DeepClone;
@Mapper(
componentModel = org.mapstruct.MappingConstants.ComponentModel.SPRING,
uses = {CommonMapper.class},
mappingControl = DeepClone.class
)
public interface ResetPwdMapper extends BaseMapper<ResetPwdEntity, ResetPwdDto, CreateResetPwdDto, UpdateResetPwdDto> {
}

View File

@@ -0,0 +1,10 @@
package cn.lihongjie.coal.resetPwd.repository;
import cn.lihongjie.coal.base.dao.BaseRepository;
import cn.lihongjie.coal.resetPwd.entity.ResetPwdEntity;
import org.springframework.stereotype.Repository;
@Repository
public interface ResetPwdRepository extends BaseRepository<ResetPwdEntity> {
}

View File

@@ -0,0 +1,168 @@
package cn.lihongjie.coal.resetPwd.service;
import cn.lihongjie.coal.base.dto.CommonQuery;
import cn.lihongjie.coal.base.dto.IdRequest;
import cn.lihongjie.coal.base.service.BaseService;
import cn.lihongjie.coal.common.Constants;
import cn.lihongjie.coal.exception.BizException;
import cn.lihongjie.coal.resetPwd.dto.ConfirmResetPasswordDto;
import cn.lihongjie.coal.resetPwd.dto.CreateResetPwdDto;
import cn.lihongjie.coal.resetPwd.dto.ResetPwdDto;
import cn.lihongjie.coal.resetPwd.dto.UpdateResetPwdDto;
import cn.lihongjie.coal.resetPwd.entity.ResetPwdEntity;
import cn.lihongjie.coal.resetPwd.mapper.ResetPwdMapper;
import cn.lihongjie.coal.resetPwd.repository.ResetPwdRepository;
import cn.lihongjie.coal.sysconfig.service.SysConfigService;
import cn.lihongjie.coal.user.entity.UserEntity;
import cn.lihongjie.coal.user.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.convert.ConversionService;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDateTime;
import java.util.Optional;
import java.util.concurrent.ThreadLocalRandom;
@Service
@Slf4j
@Transactional
public class ResetPwdService extends BaseService<ResetPwdEntity, ResetPwdRepository> {
@Autowired UserService userService;
@Autowired SysConfigService sysConfigService;
@Autowired private ResetPwdRepository repository;
@Autowired private ResetPwdMapper mapper;
@Autowired private ConversionService conversionService;
public ResetPwdDto create(CreateResetPwdDto request) {
ResetPwdEntity entity = mapper.toEntity(request);
this.repository.save(entity);
return getById(entity.getId());
}
public ResetPwdDto update(UpdateResetPwdDto request) {
ResetPwdEntity entity = this.repository.get(request.getId());
this.mapper.updateEntity(entity, request);
this.repository.save(entity);
return getById(entity.getId());
}
public void delete(IdRequest request) {
this.repository.deleteAllById(request.getIds());
}
public ResetPwdDto getById(String id) {
ResetPwdEntity entity = repository.get(id);
return mapper.toDto(entity);
}
public Page<ResetPwdDto> list(CommonQuery query) {
Page<ResetPwdEntity> page =
repository.findAll(
query.specification(conversionService),
PageRequest.of(
query.getPageNo(),
query.getPageSize(),
Sort.by(query.getOrders())));
return page.map(this.mapper::toDto);
}
public String startReset(CreateResetPwdDto dto) {
if (StringUtils.isEmpty(dto.getUserName())){
throw new RuntimeException("用户名不能为空");
}
if (StringUtils.isEmpty(dto.getEmail()) && StringUtils.isEmpty(dto.getPhone())){
throw new RuntimeException("邮箱和手机号不能同时为空");
}
if (!StringUtils.isEmpty(dto.getEmail()) && !StringUtils.isEmpty(dto.getPhone())){
throw new RuntimeException("邮箱和手机号不能同时填写");
}
Optional<UserEntity> user = userService.findByUsername(dto.getUserName());
if (!user.isPresent()){
throw new RuntimeException("用户不存在");
}
if (!StringUtils.isEmpty(dto.getEmail()) && !dto.getEmail().equals(user.get().getEmail())){
throw new RuntimeException("邮箱不正确");
}
if (!StringUtils.isEmpty(dto.getPhone()) && !dto.getPhone().equals(user.get().getPhone())){
throw new RuntimeException("手机号不正确");
}
ResetPwdEntity resetPwdEntity = new ResetPwdEntity();
resetPwdEntity.setUser(user.get());
resetPwdEntity.setPhone(dto.getPhone());
resetPwdEntity.setEmail(dto.getEmail());
resetPwdEntity.setCode(ThreadLocalRandom.current().nextInt(100000, 999999) + "");
resetPwdEntity.setFailCount(0);
resetPwdEntity.setMaxFailCount(
Integer.parseInt(
sysConfigService.getConfigVal(
Constants.SYSCONFIG_RESETPWD_MAX_FAIL_COUNT)));
resetPwdEntity.setExpireTime(
LocalDateTime.now()
.plusSeconds(
Integer.parseInt(
sysConfigService.getConfigVal(
Constants.SYSCONFIG_RESETPWD_TIMEOUT))));
this.save(resetPwdEntity);
log.info("重置密码会话创建成功: {}", resetPwdEntity);
return resetPwdEntity.getId();
}
public void confirmReset(ConfirmResetPasswordDto dto) {
ResetPwdEntity resetPwdEntity = this.repository.get(dto.getId());
if (resetPwdEntity == null){
throw new BizException("当前重置密码会话不存在, 请重新开始重置密码");
}
if (resetPwdEntity.getFailCount() >= resetPwdEntity.getMaxFailCount()){
throw new BizException("当前重置密码会话失败次数过多, 请重新开始重置密码");
}
if (resetPwdEntity.getExpireTime().isBefore(LocalDateTime.now())){
throw new BizException("当前重置密码会话已过期, 请重新开始重置密码");
}
if (!resetPwdEntity.getCode().equals(dto.getCode())){
resetPwdEntity.setFailCount(resetPwdEntity.getFailCount() + 1);
this.repository.save(resetPwdEntity);
throw new BizException("验证码不正确");
}
userService.resetPwd(resetPwdEntity.getUser().getId(), dto.getPassword());
}
}

View File

@@ -96,6 +96,45 @@ class SysConfigService extends BaseService<SysConfigEntity, SysConfigRepository>
entity.setType("2");
repository.save(entity);
}
if (!all.containsKey(Constants.SYSCONFIG_RESETPWD_ENABLE)) {
SysConfigEntity entity = new SysConfigEntity();
entity.setName("重置密码状态");
entity.setCode(Constants.SYSCONFIG_RESETPWD_ENABLE);
entity.setConfigVal("1");
entity.setDictCode("status.type");
entity.setMaxValue(null);
entity.setMinValue(null);
entity.setRegexValidator(null);
entity.setType("3");
repository.save(entity);
}
if (!all.containsKey(Constants.SYSCONFIG_RESETPWD_TIMEOUT)) {
SysConfigEntity entity = new SysConfigEntity();
entity.setName("重置密码会话超时时间s");
entity.setCode(Constants.SYSCONFIG_RESETPWD_TIMEOUT);
entity.setConfigVal(TimeUnit.MINUTES.toSeconds(10) + "");
entity.setDictCode(null);
entity.setMaxValue((int) TimeUnit.HOURS.toSeconds(24));
entity.setMinValue((int) TimeUnit.MINUTES.toSeconds(1));
entity.setRegexValidator(null);
entity.setType("2");
repository.save(entity);
}
if (!all.containsKey(Constants.SYSCONFIG_RESETPWD_MAX_FAIL_COUNT)) {
SysConfigEntity entity = new SysConfigEntity();
entity.setName("重置密码最多失败次数");
entity.setCode(Constants.SYSCONFIG_RESETPWD_MAX_FAIL_COUNT);
entity.setConfigVal(3+"");
entity.setDictCode(null);
entity.setMaxValue(Integer.MAX_VALUE);
entity.setMinValue(1);
entity.setRegexValidator(null);
entity.setType("2");
repository.save(entity);
}
}
@Autowired

View File

@@ -176,6 +176,19 @@ class UserService extends BaseService<UserEntity, UserRepository> {
return getById(request.getId());
}
public void resetPwd(String userId, String password) {
UserEntity user =
repository.findById(userId).orElseThrow(() -> new BizException("用户不存在"));
user.setPassword(passwordEncoder.encode(password));
repository.save(user);
}
public Page<UserDto> list(CommonQuery query) {
Page<UserEntity> page =