🔒 过滤用户密码在访问日志和操作日志中的存储

This commit is contained in:
b2baccline
2021-01-23 01:23:33 +08:00
parent 6efa588610
commit 9e8ba98de9
5 changed files with 107 additions and 16 deletions

View File

@@ -10,6 +10,9 @@ import com.hccake.ballcat.admin.oauth.util.SecurityUtils;
import com.hccake.ballcat.commom.log.access.handler.AccessLogHandler;
import com.hccake.ballcat.commom.log.constant.LogConstant;
import com.hccake.ballcat.commom.log.util.LogUtils;
import com.hccake.ballcat.common.core.desensite.DesensitizationHandler;
import com.hccake.ballcat.common.core.desensite.DesensitizationHandlerHolder;
import com.hccake.ballcat.common.core.desensite.DesensitizationTypeConstant;
import com.hccake.ballcat.common.core.util.IPUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@@ -20,6 +23,9 @@ import org.springframework.web.servlet.HandlerMapping;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Optional;
/**
@@ -39,6 +45,17 @@ public class AdminAccessLogHandler implements AccessLogHandler<AdminAccessLog> {
private final ObjectMapper objectMapper;
/**
* 需要脱敏记录的参数
*/
private final List<String> needDesensitizeParams = Arrays.asList("password", "pass", "passConfirm");
/**
* 脱敏处理器
*/
private final DesensitizationHandler desensitizationHandler = DesensitizationHandlerHolder.TYPE_MAPS
.get(DesensitizationTypeConstant.ENCRYPTED_PASSWORD);
/**
* 生产一个日志
* @return accessLog
@@ -53,6 +70,7 @@ public class AdminAccessLogHandler implements AccessLogHandler<AdminAccessLog> {
Object matchingPatternAttr = request.getAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE);
String matchingPattern = matchingPatternAttr == null ? "" : String.valueOf(matchingPatternAttr);
// @formatter:off
String uri = URLUtil.getPath(request.getRequestURI());
AdminAccessLog adminAccessLog = new AdminAccessLog()
.setTraceId(MDC.get(LogConstant.TRACE_ID))
.setCreateTime(LocalDateTime.now())
@@ -60,30 +78,25 @@ public class AdminAccessLogHandler implements AccessLogHandler<AdminAccessLog> {
.setIp(IPUtil.getIpAddr(request))
.setMethod(request.getMethod())
.setUserAgent(request.getHeader("user-agent"))
.setUri(URLUtil.getPath(request.getRequestURI()))
.setUri(uri)
.setMatchingPattern(matchingPattern)
.setErrorMsg(Optional.ofNullable(myThrowable).map(Throwable::getMessage).orElse(""))
.setHttpStatus(response.getStatus());
// @formatter:on
// 参数获取
String params = "";
try {
params = objectMapper.writeValueAsString(request.getParameterMap());
}
catch (JsonProcessingException e) {
log.error("[prodLog],参数获取序列化异常", e);
}
String params = getParams(request);
adminAccessLog.setReqParams(params);
// 非文件上传请求记录body
if (!LogUtils.isMultipartContent(request)) {
// 非文件上传请求记录body用户改密时不记录body
// TODO 使用注解控制此次请求是否记录body更方便个性化定制
if (!LogUtils.isMultipartContent(request) && "/sysuser/pass/{userId}".equals(uri)) {
adminAccessLog.setReqBody(LogUtils.getRequestBody(request));
}
// 只记录响应头为 application/json 的返回数据
// 后台日志对于分页数据请求,不记录返回值
if (!request.getRequestURI().endsWith("/page") && response.getContentType() != null
if (!uri.endsWith("/page") && response.getContentType() != null
&& response.getContentType().contains(APPLICATION_JSON)) {
adminAccessLog.setResult(LogUtils.getResponseBody(request, response));
}
@@ -97,6 +110,30 @@ public class AdminAccessLogHandler implements AccessLogHandler<AdminAccessLog> {
return adminAccessLog;
}
/**
* 获取参数信息
* @param request 请求信息
* @return 请求参数
*/
public String getParams(HttpServletRequest request) {
String params;
try {
Map<String, String[]> parameterMap = request.getParameterMap();
for (String paramKey : needDesensitizeParams) {
String[] values = parameterMap.get(paramKey);
if (values != null && values.length != 0) {
parameterMap.put(paramKey, new String[] { desensitizationHandler.handle(values[0]) });
}
}
params = objectMapper.writeValueAsString(parameterMap);
}
catch (JsonProcessingException e) {
params = "记录参数异常";
log.error("[prodLog],参数获取序列化异常", e);
}
return params;
}
/**
* 记录日志
* @param accessLog 访问日志

View File

@@ -1,9 +1,9 @@
package com.hccake.ballcat.admin.modules.sys.controller;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.hccake.ballcat.admin.constants.SysUserConst;
import com.hccake.ballcat.admin.modules.sys.model.dto.SysUserDTO;
import com.hccake.ballcat.admin.modules.sys.model.dto.SysUserPassDTO;
import com.hccake.ballcat.admin.modules.sys.model.dto.SysUserScope;
import com.hccake.ballcat.admin.modules.sys.model.entity.SysRole;
import com.hccake.ballcat.admin.modules.sys.model.entity.SysUser;
@@ -25,6 +25,7 @@ import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
@@ -42,6 +43,7 @@ import java.util.List;
* @author hccake 2020-09-24 20:16:15
*/
@Slf4j
@Validated
@RestController
@RequestMapping("/sysuser")
@Api(value = "sysuser", tags = "用户管理模块")
@@ -161,12 +163,11 @@ public class SysUserController {
@ApiOperation(value = "修改系统用户密码", notes = "修改系统用户密码")
@UpdateOperationLogging(msg = "修改系统用户密码")
@PreAuthorize("@per.hasPermission('sys:sysuser:pass')")
public R<?> updateUserPass(@PathVariable Integer userId, String pass, String confirm) {
if (StrUtil.isBlank(pass) || StrUtil.isBlank(confirm) || !pass.equals(confirm)) {
public R<?> updateUserPass(@PathVariable Integer userId, @RequestBody SysUserPassDTO sysUserPassDTO) {
if (!sysUserPassDTO.getPass().equals(sysUserPassDTO.getConfirmPass())) {
return R.failed(SystemResultCode.BAD_REQUEST, "错误的密码!");
}
return sysUserService.updateUserPass(userId, pass) ? R.ok()
return sysUserService.updateUserPass(userId, sysUserPassDTO.getPass()) ? R.ok()
: R.failed(BaseResultCode.UPDATE_DATABASE_ERROR, "修改用户密码失败!");
}

View File

@@ -1,5 +1,7 @@
package com.hccake.ballcat.admin.modules.sys.model.dto;
import com.hccake.ballcat.common.core.desensite.DesensitizationTypeConstant;
import com.hccake.ballcat.common.core.desensite.JsonDesensitize;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@@ -21,6 +23,7 @@ public class SysUserDTO {
/**
* 前端传入密码
*/
@JsonDesensitize(type = DesensitizationTypeConstant.ENCRYPTED_PASSWORD)
@ApiModelProperty(value = "前端传入密码")
private String pass;

View File

@@ -0,0 +1,35 @@
package com.hccake.ballcat.admin.modules.sys.model.dto;
import com.hccake.ballcat.common.core.desensite.DesensitizationTypeConstant;
import com.hccake.ballcat.common.core.desensite.JsonDesensitize;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotBlank;
/**
* 用户密码传输DTO字段序列化时忽略防止记录
*
* @author Hccake 2021/1/22
* @version 1.0
*/
@Data
public class SysUserPassDTO {
/**
* 前端传入密码
*/
@NotBlank(message = "The password cannot be empty!")
@JsonDesensitize(type = DesensitizationTypeConstant.ENCRYPTED_PASSWORD)
@ApiModelProperty(value = "前端输入密码")
private String pass;
/**
* 前端确认密码
*/
@NotBlank(message = "The confirm password cannot be empty!")
@JsonDesensitize(type = DesensitizationTypeConstant.ENCRYPTED_PASSWORD)
@ApiModelProperty(value = "前端确认密码")
private String confirmPass;
}