mirror of
https://codeup.aliyun.com/64f7d6b8ce01efaafef1e678/coal/coal.git
synced 2026-01-25 15:55:18 +08:00
添加密码字典校验
This commit is contained in:
@@ -39,6 +39,7 @@ public class Constants {
|
||||
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_PASSWORD_DICT_DETECT = "password_dict_detect";
|
||||
public static String SYSCONFIG_RESETPWD_TIMEOUT = "resetpwd_timeout";
|
||||
public static String SYSCONFIG_RESETPWD_MAX_FAIL_COUNT = "resetpwd_max_fail_count";
|
||||
public static String SYSCONFIG_SESSION_GLOBAL_RATE_LIMIT_PER_MIN = "session_global_rate_limit_per_min";
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
package cn.lihongjie.coal.passwordDict.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.passwordDict.dto.CreatePasswordDictDto;
|
||||
import cn.lihongjie.coal.passwordDict.dto.PasswordDictDto;
|
||||
import cn.lihongjie.coal.passwordDict.dto.UpdatePasswordDictDto;
|
||||
import cn.lihongjie.coal.passwordDict.service.PasswordDictService;
|
||||
|
||||
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("/passwordDict")
|
||||
@SysLog(module = "常见密码字典")
|
||||
@Slf4j
|
||||
public class PasswordDictController {
|
||||
@Autowired private PasswordDictService service;
|
||||
|
||||
@PostMapping("/create")
|
||||
public PasswordDictDto create(@RequestBody CreatePasswordDictDto request) {
|
||||
return this.service.create(request);
|
||||
}
|
||||
|
||||
@PostMapping("/update")
|
||||
public PasswordDictDto update(@RequestBody UpdatePasswordDictDto request) {
|
||||
return this.service.update(request);
|
||||
}
|
||||
|
||||
@PostMapping("/delete")
|
||||
public Object delete(@RequestBody IdRequest request) {
|
||||
this.service.delete(request);
|
||||
return true;
|
||||
}
|
||||
|
||||
@PostMapping("/getById")
|
||||
public PasswordDictDto getById(@RequestBody IdRequest request) {
|
||||
return this.service.getById(request.getId());
|
||||
}
|
||||
|
||||
@PostMapping("/list")
|
||||
public Page<PasswordDictDto> list(@RequestBody CommonQuery request) {
|
||||
return this.service.list(request);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package cn.lihongjie.coal.passwordDict.dto;
|
||||
|
||||
import cn.lihongjie.coal.base.dto.CommonDto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class CreatePasswordDictDto extends CommonDto {
|
||||
|
||||
private String pass;
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package cn.lihongjie.coal.passwordDict.dto;
|
||||
|
||||
import cn.lihongjie.coal.base.dto.CommonDto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class PasswordDictDto extends CommonDto {
|
||||
|
||||
private String pass;
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package cn.lihongjie.coal.passwordDict.dto;
|
||||
|
||||
import cn.lihongjie.coal.base.dto.CommonDto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class UpdatePasswordDictDto extends CommonDto {
|
||||
|
||||
private String pass;
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package cn.lihongjie.coal.passwordDict.entity;
|
||||
|
||||
import cn.lihongjie.coal.base.entity.CommonEntity;
|
||||
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.Index;
|
||||
import jakarta.persistence.Table;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@Entity
|
||||
@Table(indexes = {@Index(columnList = "pass", name = "idx_password_dict_pass")})
|
||||
public class PasswordDictEntity extends CommonEntity {
|
||||
|
||||
private String pass;
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package cn.lihongjie.coal.passwordDict.mapper;
|
||||
|
||||
import cn.lihongjie.coal.base.mapper.BaseMapper;
|
||||
import cn.lihongjie.coal.base.mapper.CommonMapper;
|
||||
import cn.lihongjie.coal.passwordDict.dto.CreatePasswordDictDto;
|
||||
import cn.lihongjie.coal.passwordDict.dto.PasswordDictDto;
|
||||
import cn.lihongjie.coal.passwordDict.dto.UpdatePasswordDictDto;
|
||||
import cn.lihongjie.coal.passwordDict.entity.PasswordDictEntity;
|
||||
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.control.DeepClone;
|
||||
|
||||
@Mapper(
|
||||
componentModel = org.mapstruct.MappingConstants.ComponentModel.SPRING,
|
||||
uses = {CommonMapper.class},
|
||||
mappingControl = DeepClone.class)
|
||||
public interface PasswordDictMapper
|
||||
extends BaseMapper<
|
||||
PasswordDictEntity,
|
||||
PasswordDictDto,
|
||||
CreatePasswordDictDto,
|
||||
UpdatePasswordDictDto> {}
|
||||
@@ -0,0 +1,11 @@
|
||||
package cn.lihongjie.coal.passwordDict.repository;
|
||||
|
||||
import cn.lihongjie.coal.base.dao.BaseRepository;
|
||||
import cn.lihongjie.coal.passwordDict.entity.PasswordDictEntity;
|
||||
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
@Repository
|
||||
public interface PasswordDictRepository extends BaseRepository<PasswordDictEntity> {
|
||||
int countByPass(String password);
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
package cn.lihongjie.coal.passwordDict.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.passwordDict.dto.CreatePasswordDictDto;
|
||||
import cn.lihongjie.coal.passwordDict.dto.PasswordDictDto;
|
||||
import cn.lihongjie.coal.passwordDict.dto.UpdatePasswordDictDto;
|
||||
import cn.lihongjie.coal.passwordDict.entity.PasswordDictEntity;
|
||||
import cn.lihongjie.coal.passwordDict.mapper.PasswordDictMapper;
|
||||
import cn.lihongjie.coal.passwordDict.repository.PasswordDictRepository;
|
||||
import cn.lihongjie.coal.sysconfig.service.SysConfigService;
|
||||
|
||||
import jakarta.persistence.EntityManager;
|
||||
import jakarta.persistence.PersistenceContext;
|
||||
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.core.io.Resource;
|
||||
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.io.BufferedReader;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipInputStream;
|
||||
|
||||
@Service
|
||||
@Slf4j
|
||||
@Transactional
|
||||
public class PasswordDictService extends BaseService<PasswordDictEntity, PasswordDictRepository> {
|
||||
@Value("classpath:passwordDict/dict.zip")
|
||||
Resource dictFile;
|
||||
@Autowired SysConfigService sysConfigService;
|
||||
@Autowired private PasswordDictRepository repository;
|
||||
@Autowired private PasswordDictMapper mapper;
|
||||
@Autowired private ConversionService conversionService;
|
||||
@PersistenceContext
|
||||
private EntityManager em;
|
||||
|
||||
public PasswordDictDto create(CreatePasswordDictDto request) {
|
||||
PasswordDictEntity entity = mapper.toEntity(request);
|
||||
|
||||
this.repository.save(entity);
|
||||
return getById(entity.getId());
|
||||
}
|
||||
|
||||
public PasswordDictDto update(UpdatePasswordDictDto request) {
|
||||
PasswordDictEntity 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 PasswordDictDto getById(String id) {
|
||||
PasswordDictEntity entity = repository.get(id);
|
||||
|
||||
return mapper.toDto(entity);
|
||||
}
|
||||
|
||||
public Page<PasswordDictDto> list(CommonQuery query) {
|
||||
Page<PasswordDictEntity> page =
|
||||
repository.findAll(
|
||||
query.specification(conversionService),
|
||||
PageRequest.of(
|
||||
query.getPageNo(),
|
||||
query.getPageSize(),
|
||||
Sort.by(query.getOrders())));
|
||||
|
||||
return page.map(this.mapper::toDto);
|
||||
}
|
||||
|
||||
public boolean isInDict(String password) {
|
||||
|
||||
return this.repository.countByPass(password) > 0;
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
public void initDict(){
|
||||
|
||||
if (sysConfigService.isEnable(Constants.SYSCONFIG_PASSWORD_DICT_DETECT)) {
|
||||
if (this.repository.count() == 0){
|
||||
|
||||
log.info("开始初始化密码字典");
|
||||
AtomicInteger count = new AtomicInteger();
|
||||
|
||||
try (var i = new ZipInputStream(dictFile.getInputStream())){
|
||||
|
||||
ZipEntry entry = i.getNextEntry();
|
||||
|
||||
while (entry != null){
|
||||
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(i));
|
||||
|
||||
reader.lines().forEach(x -> {
|
||||
PasswordDictEntity dict = new PasswordDictEntity();
|
||||
dict.setPass(x);
|
||||
|
||||
|
||||
this.repository.save(dict);
|
||||
|
||||
int increment = count.getAndIncrement();
|
||||
|
||||
if (increment % 10000 == 0){
|
||||
log.info("已经初始化 {} 条密码", increment);
|
||||
em.flush();
|
||||
}
|
||||
|
||||
|
||||
});
|
||||
|
||||
entry = i.getNextEntry();
|
||||
}
|
||||
|
||||
em.flush();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import cn.lihongjie.coal.coalParameterDef.service.CoalParameterDefService;
|
||||
import cn.lihongjie.coal.dictionary.service.DictionaryService;
|
||||
import cn.lihongjie.coal.organization.entity.OrganizationEntity;
|
||||
import cn.lihongjie.coal.organization.service.OrganizationService;
|
||||
import cn.lihongjie.coal.passwordDict.service.PasswordDictService;
|
||||
import cn.lihongjie.coal.permission.service.PermissionService;
|
||||
import cn.lihongjie.coal.resource.service.ResourceService;
|
||||
import cn.lihongjie.coal.script.service.ScriptService;
|
||||
@@ -47,6 +48,8 @@ public class InitDataRunner implements CommandLineRunner {
|
||||
|
||||
@Autowired UserMapper userMapper;
|
||||
|
||||
@Autowired PasswordDictService passwordDictService;
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public void run(String... args) throws Exception {
|
||||
@@ -74,6 +77,8 @@ public class InitDataRunner implements CommandLineRunner {
|
||||
|
||||
scriptService.initFromResource();
|
||||
|
||||
passwordDictService.initDict();
|
||||
|
||||
|
||||
} finally {
|
||||
SecurityContextHolder.clearContext();
|
||||
|
||||
@@ -173,6 +173,7 @@ public class SysConfigService extends BaseService<SysConfigEntity, SysConfigRepo
|
||||
Integer.MAX_VALUE);
|
||||
|
||||
|
||||
addDictConfig(all, Constants.SYSCONFIG_PASSWORD_DICT_DETECT, "密码字典检测", "1", "status.type");
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ import cn.lihongjie.coal.common.Ctx;
|
||||
import cn.lihongjie.coal.exception.BizException;
|
||||
import cn.lihongjie.coal.organization.entity.OrganizationEntity;
|
||||
import cn.lihongjie.coal.organization.service.OrganizationService;
|
||||
import cn.lihongjie.coal.passwordDict.service.PasswordDictService;
|
||||
import cn.lihongjie.coal.permission.dto.PermissionSimpleDto;
|
||||
import cn.lihongjie.coal.permission.entity.PermissionEntity;
|
||||
import cn.lihongjie.coal.permission.mapper.PermissionMapper;
|
||||
@@ -18,6 +19,7 @@ import cn.lihongjie.coal.resource.mapper.ResourceMapper;
|
||||
import cn.lihongjie.coal.resource.service.ResourceService;
|
||||
import cn.lihongjie.coal.role.entity.RoleEntity;
|
||||
import cn.lihongjie.coal.role.service.RoleService;
|
||||
import cn.lihongjie.coal.sysconfig.service.SysConfigService;
|
||||
import cn.lihongjie.coal.user.dto.*;
|
||||
import cn.lihongjie.coal.user.entity.UserEntity;
|
||||
import cn.lihongjie.coal.user.mapper.UserMapper;
|
||||
@@ -65,6 +67,9 @@ public class UserService extends BaseService<UserEntity, UserRepository> {
|
||||
|
||||
@Autowired RoleService roleService;
|
||||
|
||||
@Autowired SysConfigService sysConfigService;
|
||||
|
||||
@Autowired PasswordDictService passwordDictService;
|
||||
private Pbkdf2PasswordEncoder passwordEncoder;
|
||||
|
||||
@PostConstruct
|
||||
@@ -92,7 +97,11 @@ public class UserService extends BaseService<UserEntity, UserRepository> {
|
||||
checkDuplicateUserName(request.getUsername());
|
||||
try {
|
||||
stopWatch.start("encode");
|
||||
request.setPassword(passwordEncoder.encode(request.getPassword()));
|
||||
String password = request.getPassword();
|
||||
|
||||
checkPassDict(password);
|
||||
|
||||
request.setPassword(passwordEncoder.encode(password));
|
||||
stopWatch.stop();
|
||||
UserEntity entity = mapper.toEntity(request);
|
||||
|
||||
@@ -108,6 +117,14 @@ public class UserService extends BaseService<UserEntity, UserRepository> {
|
||||
}
|
||||
}
|
||||
|
||||
private void checkPassDict(String password) {
|
||||
if (sysConfigService.isEnable(Constants.SYSCONFIG_PASSWORD_DICT_DETECT)) {
|
||||
if (passwordDictService.isInDict(password)) {
|
||||
throw new BizException("当前密码为常见密码,请重新设置");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void checkDuplicateUserName(String username) {
|
||||
|
||||
if (this.repository.countByUsername(username) > 0) {
|
||||
@@ -119,6 +136,7 @@ public class UserService extends BaseService<UserEntity, UserRepository> {
|
||||
|
||||
StopWatch stopWatch = new StopWatch();
|
||||
checkDuplicateUserName(request.getUsername());
|
||||
checkPassDict(request.getPassword());
|
||||
try {
|
||||
stopWatch.start("encode");
|
||||
request.setPassword(passwordEncoder.encode(request.getPassword()));
|
||||
@@ -181,6 +199,8 @@ public class UserService extends BaseService<UserEntity, UserRepository> {
|
||||
throw new BizException("两次输入的密码不一致");
|
||||
}
|
||||
|
||||
checkPassDict(request.getNewPassword());
|
||||
|
||||
user.setPassword(passwordEncoder.encode(request.getNewPassword()));
|
||||
|
||||
repository.save(user);
|
||||
@@ -191,7 +211,7 @@ public class UserService extends BaseService<UserEntity, UserRepository> {
|
||||
public void resetPwd(String userId, String password) {
|
||||
|
||||
UserEntity user = repository.findById(userId).orElseThrow(() -> new BizException("用户不存在"));
|
||||
|
||||
checkPassDict(password);
|
||||
user.setPassword(passwordEncoder.encode(password));
|
||||
|
||||
repository.save(user);
|
||||
@@ -240,7 +260,7 @@ public class UserService extends BaseService<UserEntity, UserRepository> {
|
||||
|
||||
adminuser.setUsername("adminuser");
|
||||
|
||||
adminuser.setPassword(passwordEncoder.encode("abc@123"));
|
||||
adminuser.setPassword(passwordEncoder.encode("adminuser@123"));
|
||||
|
||||
adminuser.setOrgAdmin(true);
|
||||
adminuser.setName("超级管理员");
|
||||
|
||||
BIN
src/main/resources/passwordDict/dict.zip
Normal file
BIN
src/main/resources/passwordDict/dict.zip
Normal file
Binary file not shown.
Reference in New Issue
Block a user