数据加解密和完整性校验

This commit is contained in:
jiang 2024-07-24 18:07:12 +08:00
parent 998a4a0ee8
commit 043286a981
9 changed files with 126 additions and 87 deletions

View File

@ -41,7 +41,6 @@ public class TokenController {
*/
@PostMapping("login")
public R<?> login(@RequestBody LoginBody form) {
LoginUser userInfo;
if ("mobile".equals(form.getLoginType())) {
userInfo = sysLoginService.login(form.getMobile(), form.getPassword(), form.getLoginType());
@ -59,7 +58,7 @@ public class TokenController {
*/
@PostMapping("getPhoneCode")
public R<?> getPhoneCode(@RequestBody LoginBody form) {
return sysLoginService.getPhoneCode(form.getMobile(), form.getLoginType());
return sysLoginService.getPhoneCode(form.getMobile(), form.getMobileCodeType());
}
/**

View File

@ -29,6 +29,16 @@ public class LoginBody {
private String loginType;
private String mobileCodeType;
public String getMobileCodeType() {
return mobileCodeType;
}
public void setMobileCodeType(String mobileCodeType) {
this.mobileCodeType = mobileCodeType;
}
public String getMobile() {
return mobile;
}

View File

@ -3,6 +3,7 @@ package com.bonus.auth.service;
import com.bonus.auth.form.RegisterBody;
import com.bonus.common.core.constant.*;
import com.hankcs.hanlp.HanLP;
import org.apache.poi.ss.formula.functions.T;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@ -52,11 +53,11 @@ public class SysLoginService {
/**
* 获取验证码
*
* @param username 用户名或手机号
* @param loginType 登录类型register注册其他登录
* @param username 用户名或手机号
* @param getMobileCodeType 获取验证码类型register注册其他登录
* @return 响应结果
*/
public R getPhoneCode(String username, String loginType) {
public R<T> getPhoneCode(String username, String getMobileCodeType) {
long startTime = System.currentTimeMillis(); // 记录开始时间
int contactType = getContactType(username);
if (contactType == 2) {
@ -65,8 +66,7 @@ public class SysLoginService {
}
R<LoginUser> userResult = remoteUserService.getUserInfo(username, SecurityConstants.INNER);
boolean userExists = userResult != null && userResult.getData() != null;
if ("register".equals(loginType)) {
if ("register".equals(getMobileCodeType)) {
handleRegister(username, startTime, contactType, userExists);
} else {
handleLogin(username, startTime, contactType, userExists);
@ -145,35 +145,22 @@ public class SysLoginService {
* @return 登录用户信息
*/
public LoginUser login(String username, String password, String loginType) {
long startTime = System.currentTimeMillis(); // 记录开始时间
if ("mobile".equals(loginType)) {
int contactType = getContactType(username);
if (contactType == 0) {
if (!supportsEmailLogin) {
recordLogService.saveLogs(username, startTime, "邮箱登录不支持", "邮箱登录未开启", null, "失败");
throw new ServiceException("邮箱登录未开启");
}
} else if (contactType == 1) {
if (!supportsPhoneLogin) {
recordLogService.saveLogs(username, startTime, "手机登录不支持", "手机登录未开启", null, "失败");
throw new ServiceException("手机登录未开启");
}
long startTime = System.currentTimeMillis();
int contactType = getContactType(username);
if (contactType == 0) {
if (!supportsEmailLogin) {
recordLogService.saveLogs(username, startTime, "邮箱登录不支持", "邮箱登录未开启", null, "失败");
throw new ServiceException("用户名/密码错误");
}
} else if (contactType == 1) {
if (!supportsPhoneLogin) {
recordLogService.saveLogs(username, startTime, "手机登录不支持", "手机登录未开启", null, "失败");
throw new ServiceException("用户名/密码错误");
}
}// 记录开始时间
if ("mobile".equals(loginType)) {
return handleMobileLogin(username, startTime);
} else {
int contactType = getContactType(username);
if (contactType == 0) {
if (!supportsEmailLogin) {
recordLogService.saveLogs(username, startTime, "邮箱登录不支持", "邮箱登录未开启", null, "失败");
throw new ServiceException("邮箱登录未开启");
}
} else if (contactType == 1) {
if (!supportsPhoneLogin) {
recordLogService.saveLogs(username, startTime, "手机登录不支持", "手机登录未开启", null, "失败");
throw new ServiceException("手机登录未开启");
}
}
return handleUsernamePasswordLogin(username, password, startTime);
}
@ -192,7 +179,7 @@ public class SysLoginService {
LoginUser userInfo = userResult.getData();
SysUser user = userInfo.getSysUser();
validateApprovalStatus(user.getUserName(), user, startTime);
validateIpBlacklist(user.getUserName(), startTime);
validateUserStatus(user.getUserName(), user, startTime);
@ -211,16 +198,14 @@ public class SysLoginService {
private LoginUser handleUsernamePasswordLogin(String username, String password, long startTime) {
validateLoginParameters(username, password, startTime); // 验证登录参数
validateIpBlacklist(username, startTime); // IP黑名单校验
R<LoginUser> userResult = remoteUserService.getUserInfo(username, SecurityConstants.INNER);
validateUserResult(username, userResult, startTime); // 验证用户查询结果
LoginUser userInfo = userResult.getData();
SysUser user = userInfo.getSysUser();
validateApprovalStatus(username, user, startTime);
validateUserStatus(username, user, startTime); // 验证用户状态
passwordService.validate(user, password, startTime); // 验证密码
handleIpValidation(username, user, startTime); // 处理IP校验
recordLogService.saveLogs(username, startTime, "登陆成功", "用户名密码登录成功", user.getUserId().toString(), "成功");
return userInfo;
}
@ -240,12 +225,12 @@ public class SysLoginService {
if (password.length() < ValidateUtils.MIN_LENGTH || password.length() > ValidateUtils.MAX_LENGTH) {
recordLogService.saveLogs(username, startTime, "密码格式不正确", "密码格式不正确", null, "失败");
throw new ServiceException("密码格式不正确");
throw new ServiceException("用户名/密码错误");
}
if (username.length() < UserConstants.USERNAME_MIN_LENGTH || username.length() > UserConstants.USERNAME_MAX_LENGTH) {
recordLogService.saveLogs(username, startTime, "用户名格式不正确", "用户名格式不正确", null, "失败");
throw new ServiceException("用户名格式不正确");
throw new ServiceException("用户名/密码错误");
}
}
@ -282,6 +267,14 @@ public class SysLoginService {
}
}
private void validateApprovalStatus(String username, SysUser user, long startTime) {
if ("0".equals(user.getApprovalStatus())) {
recordLogService.saveLogs(username, startTime, "账号未审批", "用户不存在", null, "失败");
throw new ServiceException("账号未审批,请联系管理员");
}
}
/**
* 验证用户状态
*
@ -311,7 +304,6 @@ public class SysLoginService {
if (!nowIp.equals(hisIp)) {
recordLogService.saveErrorLogs(username, startTime, user.getUserId().toString());
}
redisService.setCacheObject("IP:" + user.getUserId().toString(), nowIp, 5L, TimeUnit.MINUTES);
} catch (Exception e) {
recordLogService.saveLogs(username, startTime, "IP校验异常", e.getMessage(), null, "失败");
@ -357,6 +349,7 @@ public class SysLoginService {
sysUser.setUserName(registerBody.getUsername());
sysUser.setNickName(registerBody.getNickName());
sysUser.setStatus("1");
sysUser.setApprovalStatus("0");
//有要求另加
sysUser.setPassword(SecurityUtils.encryptPassword(registerBody.getPassword()));

View File

@ -19,6 +19,7 @@ import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpRequestDecorator;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.util.MultiValueMap;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.util.UriComponentsBuilder;
import reactor.core.publisher.Flux;
@ -49,26 +50,12 @@ public class AecDecryptParamFilter extends AbstractGatewayFilterFactory {
log.info("解密功能已禁用,直接继续过滤链。");
return chain.filter(exchange);
}
ServerHttpRequest request = exchange.getRequest();
HttpMethod method = request.getMethod();
if (method == null) {
log.error("请求方法为 null无法处理请求。");
return chain.filter(exchange);
}
try {
if (method == HttpMethod.GET) {
return handleGetRequest(exchange, chain);
}
if (method == HttpMethod.DELETE) {
return chain.filter(exchange);
}
return handleRequest(exchange, chain);
} catch (Exception e) {
log.error("处理请求时发生错误: {}", e.getMessage(), e);
exchange.getResponse().setStatusCode(HttpStatus.INTERNAL_SERVER_ERROR);
return exchange.getResponse().setComplete();
boolean hasContentHeader = request.getHeaders().containsKey("Content-Type");
if (hasContentHeader) {
return handlePostPutRequest(exchange, chain);
} else {
return handleGetRequest(exchange, chain);
}
};
}
@ -88,7 +75,7 @@ public class AecDecryptParamFilter extends AbstractGatewayFilterFactory {
}
}
private Mono<Void> handleRequest(ServerWebExchange exchange, GatewayFilterChain chain) {
private Mono<Void> handlePostPutRequest(ServerWebExchange exchange, GatewayFilterChain chain) {
return DataBufferUtils.join(exchange.getRequest().getBody())
.flatMap(dataBuffer -> {
byte[] body = new byte[dataBuffer.readableByteCount()];
@ -178,7 +165,7 @@ public class AecDecryptParamFilter extends AbstractGatewayFilterFactory {
* 数据完整性校验
*
* @param providedHmac 请求头中的 HMAC
* @param query 请求参数
* @param query 请求参数
*/
private void integrityVerification(String providedHmac, String query) {
if (providedHmac == null) {

View File

@ -34,6 +34,7 @@ import static org.springframework.http.MediaType.MULTIPART_FORM_DATA_VALUE;
/**
* 对返回的 data数据进行加密
*
* @author 黑子
*/
@Configuration
@ -41,11 +42,11 @@ import static org.springframework.http.MediaType.MULTIPART_FORM_DATA_VALUE;
public class ResponseEncryptFilter implements GlobalFilter, Ordered {
@Value("${system.encryptEnabled}")
public boolean encryptEnabled;
public boolean encryptEnabled;
/**
* 返回的数据 是否加密
*/
public final static String KEY_HEAD="decrypt";
public final static String KEY_HEAD = "decrypt";
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
@ -54,30 +55,30 @@ public class ResponseEncryptFilter implements GlobalFilter, Ordered {
ServerHttpRequest request = exchange.getRequest();
URI uri = request.getURI();
HttpHeaders headers=request.getHeaders();
if(headers!=null){
Object object=headers.getFirst("Content-Type");
Object head=headers.getFirst(SystemGlobal.KEY_ENCRYPT);
if (head!=null){
String keyHead=head.toString();
if (SystemGlobal.KEY_ENCRYPT.equals(keyHead)){
HttpHeaders headers = request.getHeaders();
if (headers != null) {
Object object = headers.getFirst("Content-Type");
Object head = headers.getFirst(SystemGlobal.KEY_ENCRYPT);
if (head != null) {
String keyHead = head.toString();
if (SystemGlobal.KEY_ENCRYPT.equals(keyHead)) {
return chain.filter(exchange);
}
}
if(object!=null){
String contentType=object.toString();
if (contentType.contains(MULTIPART_FORM_DATA_VALUE)){
if (object != null) {
String contentType = object.toString();
if (contentType.contains(MULTIPART_FORM_DATA_VALUE)) {
return chain.filter(exchange);
}
}
}
HttpStatus statusCode = exchange.getResponse().getStatusCode();
if(Objects.equals(statusCode, HttpStatus.BAD_REQUEST) || Objects.equals(statusCode, HttpStatus.TOO_MANY_REQUESTS)){
if (Objects.equals(statusCode, HttpStatus.BAD_REQUEST) || Objects.equals(statusCode, HttpStatus.TOO_MANY_REQUESTS)) {
// 如果是特殊的请求已处理响应内容这里不再处理
return chain.filter(exchange);
}
//是否加密
if(!encryptEnabled){
if (!encryptEnabled) {
return chain.filter(exchange);
}
// 根据具体业务内容修改响应体
@ -86,11 +87,12 @@ public class ResponseEncryptFilter implements GlobalFilter, Ordered {
/**
* 修改响应体
*
* @param exchange
* @param chain
* @return
*/
private Mono<Void> modifyResponseBody(ServerWebExchange exchange, GatewayFilterChain chain) {
private Mono<Void> modifyResponseBody(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpResponse originalResponse = exchange.getResponse();
originalResponse.getHeaders().setContentType(MediaType.APPLICATION_JSON);
DataBufferFactory bufferFactory = originalResponse.bufferFactory();
@ -103,6 +105,7 @@ public class ResponseEncryptFilter implements GlobalFilter, Ordered {
public int getOrder() {
return -5;
}
@SuppressWarnings("deprecation")
private ServerHttpResponseDecorator buildResponse(ServerHttpResponse originalResponse, DataBufferFactory bufferFactory) {
return new ServerHttpResponseDecorator(originalResponse) {
@ -121,22 +124,22 @@ public class ResponseEncryptFilter implements GlobalFilter, Ordered {
System.out.println(responseData);
Map map = JSON.parseObject(responseData);
Object encrypt = map.get(SystemGlobal.KEY_DECRYPT);
Map maps= Maps.newHashMap();
if(encrypt==null || encrypt=="" || SystemGlobal.TRUE_STR.equals(encrypt)){
responseData = AesCbcUtils.encrypt(JSON.toJSONString(map));
maps.put("data",responseData);
maps.put(SystemGlobal.KEY_DECRYPT,true);
responseData=JSON.toJSONString(maps);
}else{
maps.put("data",responseData);
maps.put(SystemGlobal.KEY_DECRYPT,false);
Map maps = Maps.newHashMap();
if (encrypt == null || encrypt == "" || SystemGlobal.TRUE_STR.equals(encrypt)) {
responseData = AesCbcUtils.encrypt(JSON.toJSONString(map));
maps.put("data", responseData);
maps.put(SystemGlobal.KEY_DECRYPT, true);
responseData = JSON.toJSONString(maps);
} else {
maps.put("data", responseData);
maps.put(SystemGlobal.KEY_DECRYPT, false);
}
byte[] uppedContent = responseData.getBytes(Charsets.UTF_8);
originalResponse.getHeaders().setContentLength(uppedContent.length);
return bufferFactory.wrap(uppedContent);
}));
} else {
log.error("获取响应体数据 "+getStatusCode());
log.error("获取响应体数据 " + getStatusCode());
}
return super.writeWith(body);
}

View File

@ -66,7 +66,7 @@ public class ValidateCodeFilter extends AbstractGatewayFilterFactory<Object> {
throw new CaptchaException("请求参数异常");
}
JSONObject obj = JSON.parseObject(rspStr);
if (ObjectUtils.isNotEmpty(obj.getString("loginType")) && StringUtils.equals(obj.getString("loginType"), "mobile")) {
if (ObjectUtils.isNotEmpty(obj) && ObjectUtils.isNotEmpty(obj.getString("loginType")) && StringUtils.equals(obj.getString("loginType"), "mobile")) {
validateCodeService.checkPhoneCaptcha(obj.getString("verificationCode"), obj.getString("mobile"));
} else {
validateCodeService.checkCaptcha(obj.getString(CODE), obj.getString(UUID));

View File

@ -84,6 +84,11 @@
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
</dependencies>
<build>

View File

@ -2,15 +2,24 @@ package com.bonus.system.service.impl;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import javax.annotation.Resource;
import javax.validation.Validator;
import com.bonus.common.core.constant.CacheConstants;
import com.bonus.common.core.constant.Constants;
import com.bonus.common.core.domain.R;
import com.bonus.common.core.utils.VerificationCodeUtils;
import com.bonus.common.core.utils.sms.SmsUtils;
import com.bonus.common.redis.service.RedisService;
import org.apache.poi.ss.formula.functions.T;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
@ -73,6 +82,10 @@ public class SysUserServiceImpl implements ISysUserService {
@Autowired
protected Validator validator;
@Autowired
private JavaMailSender mailSender; // 自动注入JavaMailSender用于发送邮件
/**
* 根据条件分页查询用户列表
*
@ -528,8 +541,18 @@ public class SysUserServiceImpl implements ISysUserService {
@Override
public R<T> approvalStatus(Long userId) {
try {
SysUser sysUser = userMapper.selectUserById(userId);
if ("1".equals(sysUser.getApprovalStatus())) {
return R.fail("该用户已通过审批");
}
Integer i = userMapper.approvalStatus(userId);
if (i > 0) {
if (StringUtils.isNotEmpty(sysUser.getPhonenumber())) {
SmsUtils.smsToken(sysUser.getPhonenumber(), "您的账号:" + sysUser.getUserName() + "已通过审批,请登录系统", "");
}
if (StringUtils.isNotEmpty(sysUser.getEmail())) {
sendSimpleEmail(sysUser.getEmail(), "您的账号:" + sysUser.getUserName() + "已通过审批,请登录系统");
}
return R.ok();
} else {
return R.fail();
@ -540,4 +563,20 @@ public class SysUserServiceImpl implements ISysUserService {
}
}
/**
* 发送简单邮件
*
* @param to 接收者邮箱地址
*/
public R<Object> sendSimpleEmail(String to, String content) {
// 创建一个简单邮件消息对象
SimpleMailMessage message = new SimpleMailMessage();
message.setFrom("2642480752@qq.com"); // 发件人邮箱地址
message.setTo(to); // 收件人邮箱地址
message.setSubject("【博诺思】"); // 邮件主题
message.setText(content); // 邮件内容
mailSender.send(message); // 发送邮件
return R.ok();
}
}

View File

@ -66,6 +66,7 @@
u.create_by,
u.create_time,
u.remark,
u.approval_status,
d.dept_id,
d.parent_id,
d.ancestors,
@ -212,6 +213,7 @@
<if test="createBy != null and createBy != ''">create_by,</if>
<if test="remark != null and remark != ''">remark,</if>
<if test="loginType != null and loginType!=''">login_type,</if>
<if test="approvalStatus != null and approvalStatus!=''">approval_status,</if>
create_time
)values(
<if test="userId != null and userId != ''">#{userId},</if>
@ -227,6 +229,7 @@
<if test="createBy != null and createBy != ''">#{createBy},</if>
<if test="remark != null and remark != ''">#{remark},</if>
<if test="loginType != null and loginType!=''">#{loginType},</if>
<if test="approvalStatus != null and approvalStatus!=''">#{approvalStatus},</if>
sysdate()
)
</insert>