Commit fb1e7076 authored by ma's avatar ma

新增找回密码功能,以及一些密码限制和频率限制

parent 8c7af349
......@@ -2,8 +2,6 @@ package iot.sixiang.license.controller;
import com.acc.secret.util.RSAUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import iot.sixiang.license.consts.ResultCode;
import iot.sixiang.license.entity.User;
......@@ -15,24 +13,22 @@ import iot.sixiang.license.log.MyLog;
import iot.sixiang.license.mapper.UserMapper;
import iot.sixiang.license.model.BaseResult;
import iot.sixiang.license.model.ResResult;
import iot.sixiang.license.model.dto.CheckCodeDto;
import iot.sixiang.license.model.vo.LoginReqVo;
import iot.sixiang.license.model.vo.LoginVo;
import iot.sixiang.license.model.vo.UserResetPwdVo;
import iot.sixiang.license.service.UserService;
import iot.sixiang.license.util.CommonUtil;
import iot.sixiang.license.util.EmailUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.util.DigestUtils;
import org.springframework.util.StreamUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import springfox.documentation.annotations.ApiIgnore;
import javax.annotation.Resource;
import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
/**
* 登录Controller
......@@ -47,13 +43,24 @@ public class LoginController {
EmailUtils emailUtils;
@Resource
UserMapper userMapper;
@Resource
UserService userService;
@Value("${spring.mail.to}")
private String account;
@Value("${rsa.private_key}")
private String PRIVATE_KRY;
@Value("${other.error_count.forget_pwd}")
private Integer forgetPwdMaxErrCount;
@Value("${other.error_count.check_code}")
private Integer checkCodeMaxErrCount;
@Value("${other.code_exp_time}")
private Integer codeExpTimeStr;
private static final String USER_NAME = "root";
private static final String OPERATION_CHECK = "check";
private static final String OPERATION_RESET = "reset";
/**
* 模拟用户登录
*/
......@@ -69,7 +76,7 @@ public class LoginController {
}
User user = userMapper.getUserByUserName(USER_NAME);
String name = USER_NAME;
String pwd = user.getPassword();
String pwd = user.getPassword();
LoginUser dbUser = new LoginUser(String.valueOf(user.getUserId()), user.getUserName(), user.getPassword());
if (name.equals(userName) && RSAUtil.getDecryptString(password, PRIVATE_KRY).equals(pwd)) {
// 登录错误次数
......@@ -81,7 +88,7 @@ public class LoginController {
} else {
Date curCodeDate = new Date();
if (code.equals(UserUtils.getEmailCode(account)) && curCodeDate.before(UserUtils.getEmailCodeExpTime(account))) {
//if (code.equals("123456")) {
//if (code.equals("123456")) {
String token = JwtUtil.createToken(dbUser);
LoginVo loginVo = new LoginVo();
loginVo.setAuthorization(token);
......@@ -154,11 +161,128 @@ public class LoginController {
return BaseResult.failed().setMsgValue("验证码还在有效期内");
}
String code = CommonUtil.getValidateCode();
String content = "感谢您使用实名制服务器" + "\n" + "此次登录验证码为:" + code + "(有效期分钟)。验证码提供给他人可能导致账号被盗,请勿转发或泄露。" + "\n" + "--------------------------------------------------------------" + "此邮件由系统自动发送,请勿回复此邮件" + "--------------------------------------------------------------";
String content = "感谢您使用实名制服务器" + "\n" + "此次登录验证码为:" + code + "(有效期" + codeExpTimeStr + "分钟)。验证码提供给他人可能导致账号被盗,请勿转发或泄露。" + "\n" + "--------------------------------------------------------------" + "此邮件由系统自动发送,请勿回复此邮件" + "--------------------------------------------------------------";
emailUtils.sendSimpleMail(account, "感谢您使用实名制服务器", content);
UserUtils.setEmailCode(account, code);
Date codeExpTime = new Date(System.currentTimeMillis() + 3 * 60 * 1000);
Date codeExpTime = new Date(System.currentTimeMillis() + codeExpTimeStr * 60 * 1000);
UserUtils.setEmailCodeExpTime(account, codeExpTime);
return BaseResult.success();
}
@ApiOperation(value = "发送修改密码验证码", notes = "发送修改密码验证码到邮箱")
@GetMapping("send_code/change_pwd")
public BaseResult sendChangePwdCode() {
Date emailCodeExpTime = UserUtils.getEmailCodeExpTime(account + OPERATION_CHECK);
if (emailCodeExpTime != null && emailCodeExpTime.after(new Date())) {
return BaseResult.failed().setMsgValue("验证码还在有效期内");
}
String code = CommonUtil.getValidateCode();
String content = "感谢您使用实名制服务器" + "\n" + "此次修改密码的验证码为:" + code + "(有效期" + codeExpTimeStr + "分钟)。验证码提供给他人可能导致账号被盗,请勿转发或泄露。" + "\n" + "--------------------------------------------------------------" + "此邮件由系统自动发送,请勿回复此邮件" + "--------------------------------------------------------------";
emailUtils.sendSimpleMail(account, "感谢您使用实名制服务器", content);
UserUtils.setEmailCode(account + OPERATION_CHECK, code);
Date codeExpTime = new Date(System.currentTimeMillis() + codeExpTimeStr * 60 * 1000);
UserUtils.setEmailCodeExpTime(account + OPERATION_CHECK, codeExpTime);
return BaseResult.success();
}
@ApiOperation(value = "校验验证码", notes = "校验验证码")
@PostMapping("check_code")
public BaseResult checkCode(@RequestBody CheckCodeDto checkCodeDto) {
String code = checkCodeDto.getCode();
String emailCode = UserUtils.getEmailCode(account + OPERATION_CHECK);
String codeFreezeTimeStr = UserUtils.getCodeFreezeTimeMap(account + OPERATION_CHECK);
// codeFreezeTimeStr不为空且冻结时间是今天直接报错,不是今天的话清空数据
if (!StringUtils.isEmpty(codeFreezeTimeStr)) {
if (codeFreezeTimeStr.equals(CommonUtil.getCurDateStr())) {
return BaseResult.failed().setMsgValue("今日校验次数已达" + checkCodeMaxErrCount + "次,请明日再试");
} else {
UserUtils.removeCodeErrCntMap(account + OPERATION_CHECK);
UserUtils.removeCodeFreezeTimeMap(account + OPERATION_CHECK);
}
}
Date emailCodeExpTime = UserUtils.getEmailCodeExpTime(account + OPERATION_CHECK);
if (StringUtils.isEmpty(code)) {
return BaseResult.failed().setMsgValue("验证码不能为空");
} else {
Integer codeErrCnt = UserUtils.getCodeErrCntMap(account + OPERATION_CHECK);
if (codeErrCnt == null) {
codeErrCnt = 0;
}
if (emailCodeExpTime == null || emailCodeExpTime.before(new Date())) {
if (codeErrCnt < checkCodeMaxErrCount - 1) {
UserUtils.setCodeErrCntMap(account + OPERATION_CHECK, codeErrCnt + 1);
} else {
UserUtils.setCodeFreezeTimeMap(account + OPERATION_CHECK, CommonUtil.getCurDateStr());
}
return BaseResult.failed().setMsgValue("验证码已过期,请重发");
}
if (!code.equals(emailCode)) {
if (codeErrCnt < checkCodeMaxErrCount - 1) {
UserUtils.setCodeErrCntMap(account + OPERATION_CHECK, codeErrCnt + 1);
} else {
UserUtils.setCodeFreezeTimeMap(account + OPERATION_CHECK, CommonUtil.getCurDateStr());
}
return BaseResult.failed().setMsgValue("验证码不正确,请重试");
} else {
return BaseResult.success();
}
}
}
@ApiOperation(value = "重置密码", notes = "重置密码功能")
@PostMapping("reset_pwd")
@MyLog(title = "重置密码", businessType = BusinessType.UPDATE)
public BaseResult resetPwd(@RequestBody UserResetPwdVo userResetPwdVo) {
String errCntTimeMap = UserUtils.getErrCntTimeMap(account + OPERATION_RESET);
if (!StringUtils.isEmpty(errCntTimeMap)) {
if (errCntTimeMap.equals(CommonUtil.getCurDateStr())) {
return BaseResult.failed().setMsgValue("今日尝试重置密码次数已达" + forgetPwdMaxErrCount + "次,请明日再试");
} else {
UserUtils.removeErrCntTimeMap(account + OPERATION_RESET);
UserUtils.removeErrCnt(account + OPERATION_RESET);
}
}
String newPassWord = userResetPwdVo.getPassword();
newPassWord = RSAUtil.getDecryptString(newPassWord, PRIVATE_KRY);
if (StringUtils.isEmpty(newPassWord)) {
return BaseResult.failed().setMsgValue("密码不能为空");
}
Integer errCnt = UserUtils.getErrCnt(account + OPERATION_RESET);
if (errCnt == null) {
errCnt = 0;
}
User user = userService.getUserByName(USER_NAME);
if (newPassWord.length() < 8) {
computeResetPwdErrCnt(errCnt);
return BaseResult.failed().setMsgValue("密码不得小于8位");
}
if (CommonUtil.verifyPasswordContainAccount(newPassWord, user.getUserName())) {
computeResetPwdErrCnt(errCnt);
return BaseResult.failed().setMsgValue("密码中不得包含用户名的完整字符串、大小写变位或形似变换的字符串");
}
if (CommonUtil.isKeyBoardContinuousChar(newPassWord)) {
computeResetPwdErrCnt(errCnt);
return BaseResult.failed().setMsgValue("密码不得包含键盘连续字符4个及以上");
}
if (!CommonUtil.checkPassword(newPassWord)) {
computeResetPwdErrCnt(errCnt);
return BaseResult.failed().setMsgValue("至少由大写字母、小写字母、数字与特殊符号等4类中3类混合");
}
user.setPassword(newPassWord);
boolean b = userService.updateUser(user);
if (b) {
return BaseResult.success().setMsgValue("密码修改成功");
} else {
return BaseResult.failed().setMsgValue("密码修改失败");
}
}
private void computeResetPwdErrCnt(int errCnt) {
if (errCnt < forgetPwdMaxErrCount - 1) {
UserUtils.setErrCnt(account + OPERATION_RESET, errCnt + 1);
} else {
UserUtils.setErrCntTimeMap(account + OPERATION_RESET, CommonUtil.getCurDateStr());
}
}
}
......@@ -48,6 +48,13 @@ public class UserController {
private UserService userService;
@Value("${rsa.private_key}")
private String PRIVATE_KRY;
@Value("${other.error_count.change_pwd}")
private Integer changePwdMaxErrCount;
@Value("${spring.mail.to}")
private String account;
private static final String OPERATION_CHANGE = "change";
@InitBinder
public void initBinder(WebDataBinder binder) {
......@@ -127,6 +134,15 @@ public class UserController {
@PostMapping("update_pwd")
@MyLog(title = "修改密码", businessType = BusinessType.UPDATE)
public BaseResult updatePwd(@RequestBody UserUpdatePwdVo userUpdatePwdVo) {
String errCntTimeMap = UserUtils.getErrCntTimeMap(account + OPERATION_CHANGE);
if (!StringUtils.isEmpty(errCntTimeMap)) {
if (errCntTimeMap.equals(CommonUtil.getCurDateStr())) {
return BaseResult.failed().setMsgValue("今日尝试修改密码次数已达" + changePwdMaxErrCount + "次,请明日再试");
} else {
UserUtils.removeErrCntTimeMap(account + OPERATION_CHANGE);
UserUtils.removeErrCnt(account + OPERATION_CHANGE);
}
}
String oldPassWord = userUpdatePwdVo.getOldPassWord();
String newPassWord = userUpdatePwdVo.getNewPassWord();
String userId = UserUtils.getLoginUserId();
......@@ -138,7 +154,27 @@ public class UserController {
}
oldPassWord = RSAUtil.getDecryptString(oldPassWord, PRIVATE_KRY);
newPassWord = RSAUtil.getDecryptString(newPassWord, PRIVATE_KRY);
Integer errCnt = UserUtils.getErrCnt(account + OPERATION_CHANGE);
if (errCnt == null) {
errCnt = 0;
}
if (oldPassWord.equals(user.getPassword())) {
if (newPassWord.length() < 8) {
computeChangePwdErrCnt(errCnt);
return BaseResult.failed().setMsgValue("密码不得小于8位");
}
if (CommonUtil.verifyPasswordContainAccount(newPassWord, user.getUserName())) {
computeChangePwdErrCnt(errCnt);
return BaseResult.failed().setMsgValue("密码中不得包含用户名的完整字符串、大小写变位或形似变换的字符串");
}
if (CommonUtil.isKeyBoardContinuousChar(newPassWord)) {
computeChangePwdErrCnt(errCnt);
return BaseResult.failed().setMsgValue("密码不得包含键盘连续字符4个及以上");
}
if (!CommonUtil.checkPassword(newPassWord)) {
computeChangePwdErrCnt(errCnt);
return BaseResult.failed().setMsgValue("至少由大写字母、小写字母、数字与特殊符号等4类中3类混合");
}
user.setPassword(newPassWord);
boolean b = userService.updateUser(user);
if (b) {
......@@ -147,10 +183,19 @@ public class UserController {
return BaseResult.failed().setMsgValue("密码修改失败");
}
} else {
computeChangePwdErrCnt(errCnt);
return BaseResult.failed().setMsgValue("原密码出错");
}
}
private void computeChangePwdErrCnt(int errCnt) {
if (errCnt < changePwdMaxErrCount - 1) {
UserUtils.setErrCnt(account + OPERATION_CHANGE, errCnt + 1);
} else {
UserUtils.setErrCntTimeMap(account + OPERATION_CHANGE, CommonUtil.getCurDateStr());
}
}
/**
* 分页查询所有的user
......@@ -184,7 +229,7 @@ public class UserController {
List<UserVo> result = records.getResult();
String str = "uBtWZTiPMYkQLsp7rNly3RUIXKGqFbjnSg56H8ve49AC0mfO";
for (UserVo u : result) {
u.setPassword(DigestUtils.md5DigestAsHex((str+u.getPassword()).getBytes()));
u.setPassword(DigestUtils.md5DigestAsHex((str + u.getPassword()).getBytes()));
}
return new PageResult(200, "查找成功", pageNo, pages, total, result);
}
......
......@@ -25,6 +25,8 @@ public class JwtFilter implements Filter {
private static final String url4 = "/v2/api-docs";
private static final String url7 = "/swagger-resources";
private static final String url8 = "/webjars/";
private static final String url9 = "/check_code";
private static final String url10 = "/reset_pwd";
@Override
public void init(FilterConfig filterConfig) {
......@@ -49,7 +51,7 @@ public class JwtFilter implements Filter {
boolean check = true;
String uri = request.getRequestURI();
if (uri.contains(url1) || uri.contains(url2) || uri.contains(url3) || uri.contains(url4) || uri.contains(url7) || uri.contains(url8)) {
if (uri.contains(url1) || uri.contains(url2) || uri.contains(url3) || uri.contains(url4) || uri.contains(url7) || uri.contains(url8) || uri.contains(url9) || uri.contains(url10)) {
if (uri.contains(url1)) {
uri = XssUtil.checkXSS(uri);
UserUtils.setUri(uri);
......
......@@ -13,9 +13,13 @@ public abstract class UserUtils {
static Map<String, String> tokenMap = new HashMap<>();
static Map<String, Date> tokenExpTimeMap = new HashMap<>();
static Map<String, Integer> errCntMap = new HashMap<>();
static Map<String, String> errCntTimeMap = new HashMap<>();
static Map<String, String> emailCodeMap = new HashMap<>();
static Map<String, Date> emailCodeExpTimeMap = new HashMap<>();
static Map<String, Date> countFreezeDateMap = new HashMap<>();
static Map<String, Integer> codeErrCntMap = new HashMap<>();
static Map<String, String> codeFreezeTimeMap = new HashMap<>();
/**
* 线程变量,存放user实体类信息,即使是静态的也与其他线程也是隔离的
*/
......@@ -136,8 +140,43 @@ public abstract class UserUtils {
return emailCodeExpTimeMap.get(email);
}
public static void removeEmailCodeExpTime(String email) {
emailCodeExpTimeMap.remove(email);
}
public static void setCodeErrCntMap(String account, int count) {
codeErrCntMap.put(account, count);
}
public static Integer getCodeErrCntMap(String account) {
return codeErrCntMap.get(account);
}
public static void removeCodeErrCntMap(String account) {
codeErrCntMap.remove(account);
}
public static void setCodeFreezeTimeMap(String account, String timeStr) {
codeFreezeTimeMap.put(account, timeStr);
}
public static String getCodeFreezeTimeMap(String account) {
return codeFreezeTimeMap.get(account);
}
public static void removeCodeFreezeTimeMap(String account) {
codeFreezeTimeMap.remove(account);
}
public static void setErrCntTimeMap(String account, String timeStr) {
errCntTimeMap.put(account, timeStr);
}
public static String getErrCntTimeMap(String account) {
return errCntTimeMap.get(account);
}
public static void removeErrCntTimeMap(String account) {
errCntTimeMap.remove(account);
}
}
package iot.sixiang.license.model.dto;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
* Created by m33
* Date 2022/9/23 17:46
* Description
*/
@Data
public class CheckCodeDto {
@ApiModelProperty("验证码")
private String code;
}
package iot.sixiang.license.model.vo;
import lombok.Data;
/**
* Created by m33
* Date 2022/9/23 18:32
* Description
*/
@Data
public class UserResetPwdVo {
private String password;
}
......@@ -6,13 +6,13 @@ import iot.sixiang.license.model.vo.UserVo;
/**
* <p>
* 服务类
* 服务类
* </p>
*
* @author m33
* @since 2022-06-06
*/
public interface UserService{
public interface UserService {
boolean deleteUser(int userIdVo);
......@@ -23,4 +23,6 @@ public interface UserService{
PageInfoModel<UserVo> getUserList(int pageNo, int pageSize, String userName, String company);
User getUserById(int userId);
User getUserByName(String root);
}
package iot.sixiang.license.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import iot.sixiang.license.consts.ResultCode;
import iot.sixiang.license.entity.User;
......@@ -21,7 +22,7 @@ import java.util.stream.Collectors;
/**
* <p>
* 服务实现类
* 服务实现类
* </p>
*
* @author m33
......@@ -34,11 +35,11 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements Us
UserMapper userMapper;
@Override
public PageInfoModel<UserVo> getUserList(int pageNo, int pageSize,String userName, String company) {
if(pageNo == 0 || pageSize == 0) {
throw new IotLicenseException(ResultCode.VALIDATE_FAILED.getCode(),ResultCode.VALIDATE_FAILED.getMsg());
public PageInfoModel<UserVo> getUserList(int pageNo, int pageSize, String userName, String company) {
if (pageNo == 0 || pageSize == 0) {
throw new IotLicenseException(ResultCode.VALIDATE_FAILED.getCode(), ResultCode.VALIDATE_FAILED.getMsg());
}
List<UserVo> records = userMapper.getUserList(userName,company);
List<UserVo> records = userMapper.getUserList(userName, company);
records = records.stream().sorted(Comparator.comparing(UserVo::getCreateTime, Comparator.reverseOrder())).collect(Collectors.toList());
List<UserVo> result = new ArrayList<>();
int begin = (pageNo - 1) * pageSize;
......@@ -56,10 +57,17 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements Us
return userMapper.getUserById(userId);
}
@Override
public User getUserByName(String root) {
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(User::getUserName, root).last("limit 1");
return userMapper.selectOne(wrapper);
}
@Override
public boolean deleteUser(int userId) {
if(userId == 0) {
throw new IotLicenseException(ResultCode.VALIDATE_FAILED.getCode(),ResultCode.VALIDATE_FAILED.getMsg());
if (userId == 0) {
throw new IotLicenseException(ResultCode.VALIDATE_FAILED.getCode(), ResultCode.VALIDATE_FAILED.getMsg());
}
return userMapper.deleteUser(userId);
}
......@@ -73,7 +81,7 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements Us
if (res != null) {
throw new IotLicenseException(403, "用户名已存在");
}
return userMapper.addUser(userName,company,password);
return userMapper.addUser(userName, company, password);
}
@Override
......
......@@ -4,6 +4,7 @@ import iot.sixiang.license.consts.Consts;
import iot.sixiang.license.model.ResResult;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.util.TextUtils;
import org.springframework.boot.system.ApplicationHome;
import java.io.File;
......@@ -14,149 +15,289 @@ import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Locale;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@Slf4j
public class CommonUtil {
/**
* 获取随机验证码
*/
public static String getValidateCode() {
SecureRandom random = new SecureRandom();
try {
random = SecureRandom.getInstance("SHA1PRNG");
} catch (NoSuchAlgorithmException e) {
log.error(e.getMessage());
}
StringBuilder validateCode = new StringBuilder();
for (int i = 0; i < 6; i++) {
validateCode.append(random.nextInt(10));
}
return validateCode.toString();
}
/**
* 随机生成指定长度的字符串
*
* @param length
* @return
*/
public static String genRandomNum(int length) {
int maxNum = 36;
int i = -1;
int count = 0;
char[] str = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S',
'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' };
StringBuilder pwd = new StringBuilder("");
SecureRandom secureRandom = null;
try {
secureRandom = SecureRandom.getInstance("SHA1PRNG");
} catch (NoSuchAlgorithmException e) {
log.error("随机生成字符串失败");
}
while (count < length) {
if (secureRandom != null) {
i = Math.abs(secureRandom.nextInt(maxNum));
}
if (i >= 0 && i < str.length) {
pwd.append(str[i]);
count++;
}
}
return pwd.toString();
}
public static String getSystemTime() {
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");// 设置日期格式
String time = df.format(new Date());
return time;
}
public static boolean regularMessage(String message) {
String regex = "^[0-9a-zA-Z_]{1,}$";
return message.matches(regex);
}
public static String toUpperCaseByEnglish(String message) {
return message.toUpperCase(Locale.ENGLISH);
}
public static String bytesToStr(byte[] bytes) {
String str = null;
if (bytes == null) {
return str;
} else {
try {
str = new String(bytes, 0, bytes.length, "utf-8");
} catch (UnsupportedEncodingException e) {
log.error("数组转换成字符串异常,{}", e.getMessage());
}
return str;
}
}
public static String getServerParentDirectory() {
return new File(new ApplicationHome(Consts.class).getSource().getParentFile().getPath()).getParent()+ File.separator + "lib";
}
/**
* 名字脱敏
* 规则,张三丰,脱敏为:张*丰
*
* @param name
* @return
*/
public static String nameDesensitization(String name) {
// 已经脱敏了直接返回
if (name == null || name.contains("*")) {
return name;
}
if (name == null || name.isEmpty()) {
return "";
}
String myName = null;
char[] chars = name.toCharArray();
if (chars.length == 1) {
myName = name;
}
if (chars.length == 2) {
myName = StringUtils.overlay(name, "*", 1, 2);
}
if (chars.length > 2) {
int n = chars.length - 2;
StringBuilder s = new StringBuilder();
for (int i = 0; i < n; i++) {
s.append("*");
}
myName = StringUtils.overlay(name, String.valueOf(s), 1, chars.length - 1);
}
return myName;
}
//身份证前三后四脱敏
public static String idCardEncrypt(String idcard) {
if (idcard == null || idcard.length() == 0 || idcard.contains("*")) return idcard;
if (StringUtils.isEmpty(idcard) || (idcard.length() < 8)) {
return idcard;
}
String res = StringUtils.overlay(idcard, "**************", 0, 14);
return res;
}
// 用于测试存储型xss
public static Object reverseData(Object obj, Class clazz) {
HashMap<String, Object> resMap = new HashMap<>();
resMap.put("data", obj);
if (!PubUtils.isNull()) {
return ResResult.success().goRecord(resMap);
} else {
return null;
}
}
/**
* 验证密码-是否包含用户名字符(密码应与用户名无相关性,密码中不得包含用户名的完整字符串、大小写变位或形似变换的字符串)
*/
public static boolean verifyPasswordContainAccount(String password, String account) {
boolean isContain = false;
if (!TextUtils.isEmpty(password) && !TextUtils.isEmpty(account)) {
password = password.toLowerCase();
account = account.toLowerCase();
if (password.contains(account)) {
return true;
}
String[] likes = {"a", "l", "o"};
String[] likeSign = {"@", "!", "0"};
String originalAccount = account + "";
for (int i = 0; i < likes.length; i++) {
String tempAccount = originalAccount.replace(likes[i], likeSign[i]);
account = account.replace(likes[i], likeSign[i]);
if (password.contains(tempAccount) || password.contains(account)) {
return true;
}
}
}
return isContain;
}
/**
* 键盘连续字符统计4个
*
* @param str
* @return
*/
public static boolean isKeyBoardContinuousChar(String str) {
boolean result = false;
char[][] c1 = {
{'!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+'},
{'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '{', '}', '|'},
{'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ':', '"'},
{'z', 'x', 'c', 'v', 'b', 'n', 'm', '<', '>', '?'}
};
char[][] c2 = {
{'1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '='},
{'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '{', '}', '\\'},
{'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '\''},
{'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/'}
};
for (char[][] c : new char[][][]{c1, c2}) {
//横向
for (char[] chars : c) {
for (int j = 0; j < chars.length - 3; j++) {
//创建连续字符
StringBuffer sb = new StringBuffer();
for (int k = j; k < j + 4; k++) {
sb.append(chars[k]);
}
String keyStr = sb.toString();
if (str.contains(keyStr)) {
return true;
}
}
}
//纵向
for (int i = 0; i < c[3].length; i++) {
//创建连续字符--每列只有4个
StringBuffer sb = new StringBuffer();
for (int j = 0; j < 4; j++) {
sb.append(c[j][i]);
}
String keyStr = sb.toString();
if (str.contains(keyStr)) {
return true;
}
}
}
return result;
}
public static void main(String[] args) {
boolean b = checkPassword("1234qwe123");
System.out.println(b);
}
/**
* 密码验证
* (至少由8位及以上大写字母、小写字母、数字与特殊符号等4类中3类混合)
*
* @param password
* @return
*/
public static boolean checkPassword(String password) {
boolean flag = false;
try {
int c = 0;
if (find("[a-z]+", password)) {
c++;
}
if (find("[A-Z]+", password)) {
c++;
}
if (find("[0-9]+", password)) {
c++;
}
if (find("\\W+|_", password) && !find("\\s+", password)) {//特殊符号
c++;
}
if (c >= 3) {
flag = true;
}
} catch (Exception e) {
flag = false;
}
return flag;
}
//通用匹配
public static boolean find(String regexStr, String input) {
boolean flag;
try {
Pattern regex = Pattern.compile(regexStr);
Matcher matcher = regex.matcher(input);
// 部分进行匹配
flag = matcher.find();
} catch (Exception e) {
flag = false;
}
return flag;
}
/**
* 获取随机验证码
*/
public static String getValidateCode() {
SecureRandom random = new SecureRandom();
try {
random = SecureRandom.getInstance("SHA1PRNG");
} catch (NoSuchAlgorithmException e) {
log.error(e.getMessage());
}
StringBuilder validateCode = new StringBuilder();
for (int i = 0; i < 6; i++) {
validateCode.append(random.nextInt(10));
}
return validateCode.toString();
}
/**
* 随机生成指定长度的字符串
*
* @param length
* @return
*/
public static String genRandomNum(int length) {
int maxNum = 36;
int i = -1;
int count = 0;
char[] str = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S',
'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'};
StringBuilder pwd = new StringBuilder("");
SecureRandom secureRandom = null;
try {
secureRandom = SecureRandom.getInstance("SHA1PRNG");
} catch (NoSuchAlgorithmException e) {
log.error("随机生成字符串失败");
}
while (count < length) {
if (secureRandom != null) {
i = Math.abs(secureRandom.nextInt(maxNum));
}
if (i >= 0 && i < str.length) {
pwd.append(str[i]);
count++;
}
}
return pwd.toString();
}
public static String getSystemTime() {
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");// 设置日期格式
String time = df.format(new Date());
return time;
}
public static boolean regularMessage(String message) {
String regex = "^[0-9a-zA-Z_]{1,}$";
return message.matches(regex);
}
public static String toUpperCaseByEnglish(String message) {
return message.toUpperCase(Locale.ENGLISH);
}
public static String bytesToStr(byte[] bytes) {
String str = null;
if (bytes == null) {
return str;
} else {
try {
str = new String(bytes, 0, bytes.length, "utf-8");
} catch (UnsupportedEncodingException e) {
log.error("数组转换成字符串异常,{}", e.getMessage());
}
return str;
}
}
public static String getServerParentDirectory() {
return new File(new ApplicationHome(Consts.class).getSource().getParentFile().getPath()).getParent() + File.separator + "lib";
}
/**
* 名字脱敏
* 规则,张三丰,脱敏为:张*丰
*
* @param name
* @return
*/
public static String nameDesensitization(String name) {
// 已经脱敏了直接返回
if (name == null || name.contains("*")) {
return name;
}
if (name == null || name.isEmpty()) {
return "";
}
String myName = null;
char[] chars = name.toCharArray();
if (chars.length == 1) {
myName = name;
}
if (chars.length == 2) {
myName = StringUtils.overlay(name, "*", 1, 2);
}
if (chars.length > 2) {
int n = chars.length - 2;
StringBuilder s = new StringBuilder();
for (int i = 0; i < n; i++) {
s.append("*");
}
myName = StringUtils.overlay(name, String.valueOf(s), 1, chars.length - 1);
}
return myName;
}
//身份证前三后四脱敏
public static String idCardEncrypt(String idcard) {
if (idcard == null || idcard.length() == 0 || idcard.contains("*")) return idcard;
if (StringUtils.isEmpty(idcard) || (idcard.length() < 8)) {
return idcard;
}
String res = StringUtils.overlay(idcard, "**************", 0, 14);
return res;
}
public static String getCurDateStr() {
Date date = new Date();
String pattern = "yyyy-MM-dd";
SimpleDateFormat simpleDateFormat = new SimpleDateFormat(pattern);
return simpleDateFormat.format(date);
}
// 用于测试存储型xss
public static Object reverseData(Object obj, Class clazz) {
HashMap<String, Object> resMap = new HashMap<>();
resMap.put("data", obj);
if (!PubUtils.isNull()) {
return ResResult.success().goRecord(resMap);
} else {
return null;
}
}
}
......@@ -32,12 +32,18 @@ server:
cros:
# 需要设置访问白名单
cros_allowed_origins: http://192.168.1.88:8080, http://localhost:8868, http://localhost:8080
cros_allowed_origins: http://192.168.1.88:8080, http://192.168.1.88:8081, http://localhost:8868, http://localhost:8080, http://192.168.1.54:8080
cros_allowed_method: GET,POST
other:
md5:
salt: PI7dBYlEfeP8IZ6vogqFL1U5pVnyCuNAGja3lsREx4M9r0SX
error_count:
change_pwd: 5 # 修改密码的最大错误次数
forget_pwd: 5 # 忘记密码的最大错误次数
check_code: 5 # 校验验证码的最大错误次数
code_exp_time: 3 # 验证码失效时间,单位:分钟
rsa:
public_key: MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA18W2H1hO98dUWf1PNKNWTWmxCyvvy0NOR7iSvp76J0LdzyMJxs8WHVAmRfSGOb9SvpDZhBVx11bhTBqkl1qMzJWzn+F2ZtTCH2nXZcJHwSfLuGqin5FRBYW1WrFkqwg+R80aOuRSrbo0k1bZg3JPkkCxISHieEZPjSV5a4r7+Xopj0a9Dnh3rh4nDmH2p/wvotkx1oMKdhFglYcAITlk9ucEUf+CDuSdTAFFeKg9+fPqwKqWZRJZPQXqV3pGZ1/JS7gPnBFGZojW44eJufkBeiW3pbBvm/cKOkTnb8o4oltYUJsirYSQCCG+sDtxUAuGxuDCv8p+r8dWE1z5+xKclQIDAQAB
private_key: MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDXxbYfWE73x1RZ/U80o1ZNabELK+/LQ05HuJK+nvonQt3PIwnGzxYdUCZF9IY5v1K+kNmEFXHXVuFMGqSXWozMlbOf4XZm1MIfaddlwkfBJ8u4aqKfkVEFhbVasWSrCD5HzRo65FKtujSTVtmDck+SQLEhIeJ4Rk+NJXlrivv5eimPRr0OeHeuHicOYfan/C+i2THWgwp2EWCVhwAhOWT25wRR/4IO5J1MAUV4qD358+rAqpZlElk9BepXekZnX8lLuA+cEUZmiNbjh4m5+QF6JbelsG+b9wo6ROdvyjiiW1hQmyKthJAIIb6wO3FQC4bG4MK/yn6vx1YTXPn7EpyVAgMBAAECggEAR7YQ+kfqLtVThnj2mwLyCtZmndTjZEWhPZrtQmcpsmS5vT7i3+0xZ1qc7cD/3y9j+6u+bvSFmlDondd4/kh85P2X7joLlM9/GNufV9WC7YIhZdAi7i9ooxI2HMc6MtGRiWF0J0B87folwRYrQlF6epv/goh1cQ3FIJ7kxMYzSk0gF0JcmOZn3KH8tMt3t/GK+uVUIycuEQQKsaTTq45nIM7oqhlAwD/M+IO2pGFkLXJ23FzFACI10qBdpn+xL2xFGRO6EE8EAeDslT4OvvN3/vtnSnRNn8CJqfoEG40XO0xrZzH1noI35iPWX1WrN7qFLAhl2oLhu1ZSIA1tz0+I/QKBgQD3X/islXfVmV2XeuHvaf4qcMAdrgLQwtmLlHhFxfFURPh6au8uatDgUA8HWcRACmhtTruytlFRGKKFwZxuQE/LOZh67Uts3GTs5eHN8xvZTL+en+n7B/cCRYrrg3+yAM/k0eezIlk65iW700o+icEHxkwTXhhVBmIROBzpXsVCwwKBgQDfS6kVhgZxLMQePbXUQ1NBr2KbfhXLzceINhsoyWLa1rIk8+9HLSxw8q0zma12Jqkd22OAgkbeLDy+niYPi3pUrWAm8O59Ot1aaOarxMTvEv7+eS+urKId57sli/hQTWsS+xghA4+VfW2+EY++pYyZIp+j+1/Q2ciXWVJy4iv9xwKBgFzW8+kxn2vWxz1WrPzBdtZOwothB0V6G1M7QXhONag+ylKHV4TAKexFn55Onky6mz6K0f7cVeBtsnEonKD0Gf5Xe1aHQEt225ndHMXCe60uFKxfr9y6vIVpvB1vmLkhfOSPsrmUJpDoVzkKr06RPJTCY0LRiag/YQa9XHxpSPcpAoGAKbsiJnudyJjtLhmqWbkbXjNA4n515FjY6YPzH3RDnVJyiKVuGoc+vv0bkYEvAd3HzWSq++FdDTiHQbictFsEyb59McnlSFIv/C2Orptfkq6iKTzMxIBO6/fa6fF2vss5L5rtr33S38VJNTRjAOY/mH74BtV72rRY4LA40G+keRECgYEAiGg0DYxcSGf2bEP1WESYPTTdgS5ke1niIwZ00SgtkIjPSVgTCmf4Tciys6lGSe/Oqnvk24VR6pz07wzcbH92AURVaeqiEvVuVonzA6Yl0jxeOIM31S1BSBJRT8kDijuvwoJu2tPoZG0306KF9L8pyy1Z6cTTmIfGR0NpZCHWPSg=
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment