From 0c820746a96a1193a64532b3b17b08d52e4ff1be Mon Sep 17 00:00:00 2001
From: zhongrj <646384940@qq.com>
Date: Mon, 11 Sep 2023 19:13:15 +0800
Subject: [PATCH] 1. 登录记录新增 2. 用户6个月,1年未登录定时任务新增 3. 脱敏 aop 注解新增
---
src/main/java/org/springblade/modules/system/mapper/UserMapper.xml | 43 ++++++
src/main/java/org/springblade/common/desensitization/Desensitization.java | 28 ++++
src/main/resources/application-test.yml | 6
pom.xml | 6
src/main/java/org/springblade/modules/quartz/task/Task.java | 23 +++
src/main/java/org/springblade/modules/test/TestController.java | 75 ++++++++++
src/main/java/org/springblade/modules/auth/endpoint/BladeTokenEndPoint.java | 16 +
src/main/java/org/springblade/modules/system/service/impl/UserServiceImpl.java | 22 +++
src/main/java/org/springblade/common/desensitization/DesensitizationWord.java | 16 ++
src/main/java/org/springblade/common/desensitization/DesensitizationAspect.java | 143 ++++++++++++++++++++
src/main/java/org/springblade/modules/system/mapper/UserMapper.java | 20 ++
src/main/java/org/springblade/modules/system/service/IUserService.java | 10 +
src/main/resources/application.yml | 1
13 files changed, 397 insertions(+), 12 deletions(-)
diff --git a/pom.xml b/pom.xml
index caf2bcc..c58de87 100644
--- a/pom.xml
+++ b/pom.xml
@@ -294,7 +294,11 @@
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
-
+ <dependency>
+ <groupId>cn.hutool</groupId>
+ <artifactId>hutool-all</artifactId>
+ <version>5.7.16</version>
+ </dependency>
</dependencies>
<profiles>
<profile>
diff --git a/src/main/java/org/springblade/common/desensitization/Desensitization.java b/src/main/java/org/springblade/common/desensitization/Desensitization.java
new file mode 100644
index 0000000..16e5222
--- /dev/null
+++ b/src/main/java/org/springblade/common/desensitization/Desensitization.java
@@ -0,0 +1,28 @@
+package org.springblade.common.desensitization;
+
+import cn.hutool.core.util.DesensitizedUtil;
+
+import java.lang.annotation.*;
+
+import static cn.hutool.core.util.DesensitizedUtil.DesensitizedType.FIXED_PHONE;
+
+/**
+ * 脱敏
+ * @author zhongrj
+ * @date 2023-09-11
+ */
+public @interface Desensitization {
+
+ /**
+ * json path 的标识
+ * @return
+ */
+ String jsonPath();
+
+ /**
+ * 脱敏的字段的数据分类, 默认是座机号码类型脱敏
+ * @return
+ */
+ DesensitizedUtil.DesensitizedType desensitizedType() default FIXED_PHONE;
+
+}
diff --git a/src/main/java/org/springblade/common/desensitization/DesensitizationAspect.java b/src/main/java/org/springblade/common/desensitization/DesensitizationAspect.java
new file mode 100644
index 0000000..d9ea963
--- /dev/null
+++ b/src/main/java/org/springblade/common/desensitization/DesensitizationAspect.java
@@ -0,0 +1,143 @@
+package org.springblade.common.desensitization;
+
+import cn.hutool.core.convert.Convert;
+import cn.hutool.core.util.DesensitizedUtil;
+import cn.hutool.core.util.StrUtil;
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import com.alibaba.fastjson.JSONPath;
+import liquibase.util.StringUtils;
+import lombok.extern.slf4j.Slf4j;
+import org.aspectj.lang.ProceedingJoinPoint;
+import org.aspectj.lang.annotation.Around;
+import org.aspectj.lang.annotation.Aspect;
+import org.springblade.core.secure.utils.AuthUtil;
+import org.springframework.stereotype.Component;
+
+import static cn.hutool.core.util.DesensitizedUtil.DesensitizedType.FIXED_PHONE;
+
+/**
+ * 数据脱敏切面
+ * @author zhongrj
+ * @date 2023-09-11
+ */
+@Slf4j
+@Aspect
+@Component
+public class DesensitizationAspect {
+
+ /**
+ * 脱敏环绕通知
+ * @param pjp
+ * @param desensitizationWord
+ * @return
+ * @throws Throwable
+ */
+ @Around("@annotation(desensitizationWord)")
+ public Object around(ProceedingJoinPoint pjp, DesensitizationWord desensitizationWord) throws Throwable{
+ Object object = pjp.proceed();
+ // 判断是否需要脱敏处理
+ if (isDesensitization()) {
+ try {
+ Class<?> aClass = object.getClass();
+ // 改变返回值
+ Desensitization[] value = desensitizationWord.value();
+ JSONObject ob = JSON.parseObject(JSON.toJSONString(object));
+
+ // 循环处理每一个 json 路径下的值
+ for (Desensitization s : value) {
+ replace(ob, s);
+ }
+ object = JSON.parseObject(JSON.toJSONString(ob), aClass);
+ } catch (Exception e) {
+ log.info("数据脱敏失败:" + e.getMessage());
+ }
+ }
+ return object;
+ }
+
+ /**
+ * 判断是否需要脱敏
+ * @return
+ */
+ private boolean isDesensitization() {
+ // 获取用户角色,根据角色判断是否进行脱敏处理
+ String userRole = AuthUtil.getUserRole();
+ // 如果用户角色为null,则需要脱敏
+ if (null!=userRole && !userRole.equals("")){
+ // 判断角色是否为民警角色,如果是则不需要脱敏,否则需要脱敏处理
+ if (userRole.equals("民警")){
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * 脱敏
+ */
+ private Object sensitiveByString(Object value) {
+ if (StringUtils.isNotEmpty(value.toString())) {
+ String st = Convert.toStr(value);
+ st = st.substring(0, st.length() - 3 > 0 ? 3 : st.length()) + "****" + st.substring(Math.max(st.length() - 4, 0));
+ return st;
+ }
+ return value;
+ }
+
+ /**
+ * 敏感数据替换
+ *
+ * @param jsonObject
+ * @param s
+ */
+ private void replace(JSONObject jsonObject, Desensitization s) {
+ // 只有传入的 JSON 路径在 这个 JSONObject 中才会进行脱敏处理
+ if (JSONPath.contains(jsonObject, s.jsonPath())) {
+
+ // 查询是否有数组 列表 类型的数据需要脱敏
+ int index = s.jsonPath().lastIndexOf("[*]");
+ if (index > -1) {
+ String prefix = StrUtil.subPre(s.jsonPath(), index);
+ String suffix = StrUtil.subSuf(s.jsonPath(), index + 3);
+ // 提取json 路径下的 数组\链表 元素
+ Object eval = JSONPath.eval(jsonObject, prefix);
+
+ // 将数组\链表 元素 转为 JSONArray 方便做 统一格式处理
+ JSONArray jsonArray = (JSONArray) eval;
+ int size = jsonArray.size();
+ for (int i = 0; i < size; i++) {
+ // 由于脱敏数组内部的参数传入格式为 :jsonPath = "$.data.records[*].username"
+ // 所以需要重新组装 jsonPath 将 * 号 替换成具体的值
+ String indexJsonPath = StrUtil.strBuilder().append(prefix).append("[").append(i).append("]").append(suffix).toString();
+ // 使用 cn.hutool.core.convert Convert.toStr 转换为字符串 如果给定的值为null,或者转换失败,返回默认值null,这样可以减少报错,避免程序异常
+ String desensitized = Convert.toStr(JSONPath.eval(jsonObject, indexJsonPath));
+ if (StrUtil.isBlank(desensitized)) {
+ continue;
+ }
+ // 如果是默认指定 则使用默认方式脱敏
+ if (s.desensitizedType() == FIXED_PHONE) {
+ desensitized = sensitiveByString(desensitized).toString();
+ }else {
+ // 否则使用 cn.hutool.core.util 进行数据脱敏
+ desensitized = DesensitizedUtil.desensitized(desensitized, s.desensitizedType());
+ }
+
+ // 使用JSON 路径操作,将已经脱敏的新数据,放入之前未脱敏的数据地址处,替换未脱敏数据
+ JSONPath.set(jsonObject, indexJsonPath, desensitized);
+ }
+ } else {
+ // 使用 cn.hutool.core.convert Convert.toStr 转换为字符串 如果给定的值为null,或者转换失败,返回默认值null,这样可以减少报错,避免程序异常
+ Object eval = JSONPath.eval(jsonObject, Convert.toStr(s.jsonPath()));
+ String desensitized = "";
+ if (s.desensitizedType() == FIXED_PHONE) {
+ desensitized = sensitiveByString(Convert.toStr(eval)).toString();
+ }else {
+ desensitized = DesensitizedUtil.desensitized(Convert.toStr(eval), s.desensitizedType());
+ }
+ JSONPath.set(jsonObject, s.jsonPath(), desensitized);
+ }
+ }
+ }
+}
diff --git a/src/main/java/org/springblade/common/desensitization/DesensitizationWord.java b/src/main/java/org/springblade/common/desensitization/DesensitizationWord.java
new file mode 100644
index 0000000..d8b064a
--- /dev/null
+++ b/src/main/java/org/springblade/common/desensitization/DesensitizationWord.java
@@ -0,0 +1,16 @@
+package org.springblade.common.desensitization;
+
+import java.lang.annotation.*;
+
+/**
+ * 脱敏
+ * @author zhongrj
+ * @date 2023-09-11
+ */
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface DesensitizationWord {
+
+ Desensitization [] value();
+}
diff --git a/src/main/java/org/springblade/modules/auth/endpoint/BladeTokenEndPoint.java b/src/main/java/org/springblade/modules/auth/endpoint/BladeTokenEndPoint.java
index b0f4db2..5c9cafc 100644
--- a/src/main/java/org/springblade/modules/auth/endpoint/BladeTokenEndPoint.java
+++ b/src/main/java/org/springblade/modules/auth/endpoint/BladeTokenEndPoint.java
@@ -158,13 +158,17 @@
}
}
}
- }else {
- System.out.println("grantType = " + grantType);
//刷新 token 不新增登录记录
-// if (!grantType.equals("refresh_token")){
-// //新增登录记录
-// this.saveLoginRecord(userInfo);
-// }
+ if (!grantType.equals("refresh_token")){
+ //新增登录记录
+ this.saveLoginRecord(userInfo);
+ }
+ }else {
+ //刷新 token 不新增登录记录
+ if (!grantType.equals("refresh_token")){
+ //新增登录记录
+ this.saveLoginRecord(userInfo);
+ }
}
return TokenUtil.createAuthInfo(userInfo);
}
diff --git a/src/main/java/org/springblade/modules/quartz/task/Task.java b/src/main/java/org/springblade/modules/quartz/task/Task.java
index e3eaa2e..073a9cf 100644
--- a/src/main/java/org/springblade/modules/quartz/task/Task.java
+++ b/src/main/java/org/springblade/modules/quartz/task/Task.java
@@ -1,5 +1,6 @@
package org.springblade.modules.quartz.task;
+import org.springblade.modules.system.service.IUserService;
import org.springblade.modules.training.service.TrainingRegistrationService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
@@ -20,6 +21,9 @@
@Autowired
private TrainingRegistrationService trainingRegistrationService;
+ @Autowired
+ private IUserService userService;
+
public void testTask(){
System.out.println("测试定时任务执行-----------------");
}
@@ -38,11 +42,26 @@
/**
* 定时任务,处理考试中的人员
*/
-// @Scheduled(cron = "0 0 22 * * ?")
public void examLoading(){
- System.out.println("定时任务2:执行时间:"+new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
+ System.out.println("定时任务,处理考试中的人员:执行时间:"+new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
//自动处理之前报了名,考试忘记提交或者中断考试的
trainingRegistrationService.examLoading();
}
+ /**
+ * 定时任务,6个月未登录人员,进行冻结
+ */
+ public void sixMonthNotLoginHandle(){
+ System.out.println("定时任务,6个月未登录人员,进行冻结:执行时间:"+new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
+ userService.sixMonthNotLoginHandle();
+ }
+
+ /**
+ * 定时任务,12个月未登录人员,进行注销
+ */
+ public void oneYearNotLoginHandle(){
+ System.out.println("定时任务,12个月未登录人员,进行注销:执行时间:"+new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
+ userService.oneYearNotLoginHandle();
+ }
+
}
diff --git a/src/main/java/org/springblade/modules/system/mapper/UserMapper.java b/src/main/java/org/springblade/modules/system/mapper/UserMapper.java
index 5d05630..492f1a1 100644
--- a/src/main/java/org/springblade/modules/system/mapper/UserMapper.java
+++ b/src/main/java/org/springblade/modules/system/mapper/UserMapper.java
@@ -279,4 +279,24 @@
* @return
*/
User getUserByPhone(@Param("tenantId")String tenantId,@Param("phone") String phone);
+
+ /**
+ * 按天查询 day 天未登录的人员ids集合信息
+ * @param day
+ * @return
+ */
+ List<String> getMoreDayNotLoginUser(@Param("day")int day);
+
+ /**
+ * 用户冻结操作
+ * @param userIds
+ */
+ void updateFreeze(@Param("list") List<String> userIds);
+
+ /**
+ * 用户注销操作
+ * @param userIds
+ */
+ void updateLogout(@Param("list") List<String> userIds);
+
}
diff --git a/src/main/java/org/springblade/modules/system/mapper/UserMapper.xml b/src/main/java/org/springblade/modules/system/mapper/UserMapper.xml
index 6b228c0..4ee38f8 100644
--- a/src/main/java/org/springblade/modules/system/mapper/UserMapper.xml
+++ b/src/main/java/org/springblade/modules/system/mapper/UserMapper.xml
@@ -1144,5 +1144,48 @@
and tenant_id = #{tenantId} and phone = #{phone}
</select>
+ <!--按天查询 day 天未登录的人员ids集合信息-->
+ <select id="getMoreDayNotLoginUser" resultType="java.lang.String">
+ select bu.id from blade_user bu
+ left join (
+ select user_id,max(create_time) as create_time from sys_login_record GROUP BY user_id
+ )slr on bu.id = slr.user_id
+ where bu.status = 1 and bu.is_deleted = 0 and bu.role_id = 1412226235153731586
+ and DATE_SUB(CURDATE(), INTERVAL #{day} DAY) > date(bu.create_time)
+ and DATE_SUB(CURDATE(), INTERVAL #{day} DAY) > date(slr.create_time)
+ </select>
+
+ <!--用户冻结操作-->
+ <update id="updateFreeze">
+ update blade_user set is_deleted = 1
+ <choose>
+ <when test="list!=null and list.size()>0">
+ where id in
+ <foreach collection="list" item="id" open="(" close=")" separator=",">
+ #{id}
+ </foreach>
+ </when>
+ <otherwise>
+ where id in ('')
+ </otherwise>
+ </choose>
+ </update>
+
+ <!--用户注销操作-->
+ <update id="updateLogout">
+ update blade_user set is_deleted = 1
+ <choose>
+ <when test="list!=null and list.size()>0">
+ where id in
+ <foreach collection="list" item="id" open="(" close=")" separator=",">
+ #{id}
+ </foreach>
+ </when>
+ <otherwise>
+ where id in ('')
+ </otherwise>
+ </choose>
+ </update>
+
</mapper>
diff --git a/src/main/java/org/springblade/modules/system/service/IUserService.java b/src/main/java/org/springblade/modules/system/service/IUserService.java
index 87a24bc..7e05f7f 100644
--- a/src/main/java/org/springblade/modules/system/service/IUserService.java
+++ b/src/main/java/org/springblade/modules/system/service/IUserService.java
@@ -394,4 +394,14 @@
* @return
*/
UserInfo userInfoByWx(String tenantId, String phone, UserEnum web);
+
+ /**
+ * 6个月未登录人员,进行冻结
+ */
+ void sixMonthNotLoginHandle();
+
+ /**
+ * 12个月未登录人员,进行注销
+ */
+ void oneYearNotLoginHandle();
}
diff --git a/src/main/java/org/springblade/modules/system/service/impl/UserServiceImpl.java b/src/main/java/org/springblade/modules/system/service/impl/UserServiceImpl.java
index 077dd5a..0853aba 100644
--- a/src/main/java/org/springblade/modules/system/service/impl/UserServiceImpl.java
+++ b/src/main/java/org/springblade/modules/system/service/impl/UserServiceImpl.java
@@ -1991,4 +1991,26 @@
public User getUserById(String id) {
return baseMapper.getUserById(Long.parseLong(id));
}
+
+ /**
+ * 6个月未登录人员,进行冻结
+ */
+ @Override
+ public void sixMonthNotLoginHandle() {
+ // 查询6个月未登录人员
+ List<String> userIds = baseMapper.getMoreDayNotLoginUser(183);
+ // 统一冻结操作
+ baseMapper.updateFreeze(userIds);
+ }
+
+ /**
+ * 12个月未登录人员,进行注销
+ */
+ @Override
+ public void oneYearNotLoginHandle() {
+ // 查询12个月未登录人员
+ List<String> userIds = baseMapper.getMoreDayNotLoginUser(366);
+ // 统一注销操作
+ baseMapper.updateLogout(userIds);
+ }
}
diff --git a/src/main/java/org/springblade/modules/test/TestController.java b/src/main/java/org/springblade/modules/test/TestController.java
new file mode 100644
index 0000000..8fef2fe
--- /dev/null
+++ b/src/main/java/org/springblade/modules/test/TestController.java
@@ -0,0 +1,75 @@
+package org.springblade.modules.test;
+
+import com.yunpian.sdk.model.Result;
+import lombok.AllArgsConstructor;
+import org.springblade.common.desensitization.Desensitization;
+import org.springblade.common.desensitization.DesensitizationWord;
+import org.springblade.core.tool.api.R;
+import org.springblade.modules.system.entity.User;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import static cn.hutool.core.util.DesensitizedUtil.DesensitizedType.*;
+
+@AllArgsConstructor
+@RestController
+@RequestMapping("/test")
+public class TestController {
+
+
+ @GetMapping("/getUserInfo")
+ @DesensitizationWord({
+ @Desensitization(jsonPath = "$.data.name",desensitizedType = CHINESE_NAME),
+ @Desensitization(jsonPath = "$.data.phone",desensitizedType = MOBILE_PHONE),
+ @Desensitization(jsonPath = "$.data.bankCard",desensitizedType = BANK_CARD),
+ })
+ public R getUserInfo() {
+ Map<String, String> map = new HashMap<>();
+ map.put("name","张三");
+ map.put("phone","18111111111");
+ map.put("bankCard","6227112222211111211");
+ return R.data(map);
+ }
+
+ /**
+ * 对象脱敏
+ * @return
+ */
+ @GetMapping("getInfo2")
+ @DesensitizationWord({
+ @Desensitization(jsonPath = "$.data.phone",desensitizedType = MOBILE_PHONE),
+ @Desensitization(jsonPath = "$.data.realName",desensitizedType = CHINESE_NAME),
+ })
+ public R getCaseInfo2() {
+ User user = new User();
+ user.setPhone("18111111111");
+ user.setRealName("cs1");
+ return R.data(user);
+ }
+
+ /**
+ * 集合脱敏
+ * @return
+ */
+ @GetMapping("getInfo3")
+ @DesensitizationWord(@Desensitization(jsonPath = "$.data[*].phone"))
+ public R getCaseInfo(){
+ List<User> users = new ArrayList<>();
+ User user = new User();
+ user.setPhone("18111111111");
+ User user1 = new User();
+ user1.setPhone("18222222222");
+ users.add(user);
+ users.add(user1);
+ return R.data(users);
+ }
+
+
+}
diff --git a/src/main/resources/application-test.yml b/src/main/resources/application-test.yml
index cbe94e4..0d60fa4 100644
--- a/src/main/resources/application-test.yml
+++ b/src/main/resources/application-test.yml
@@ -15,7 +15,7 @@
# MySql
url: jdbc:mysql://127.0.0.1:3308/zhbaw_test?useSSL=false&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&transformedBitIsBoolean=true&serverTimezone=GMT%2B8&nullCatalogMeansCurrent=true&allowPublicKeyRetrieval=true
username: root
- password: 123456
+ password: root
# rabbitmq 设置
# rabbitmq:
# host: 192.168.0.191
@@ -79,9 +79,9 @@
enable: stop
type: sql
driver: com.mysql.cj.jdbc.Driver
- url: jdbc:mysql://106.225.193.35:3306/zhbaw-test?useSSL=false&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&transformedBitIsBoolean=true&serverTimezone=GMT%2B8&nullCatalogMeansCurrent=true&allowPublicKeyRetrieval=true
+ url: jdbc:mysql://127.0.0.1:3308/zhbaw_test?useSSL=false&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&transformedBitIsBoolean=true&serverTimezone=GMT%2B8&nullCatalogMeansCurrent=true&allowPublicKeyRetrieval=true
username: root
- password: HCyj@2022
+ password: root
#第三方登陆
social:
diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml
index 951e481..8758f83 100644
--- a/src/main/resources/application.yml
+++ b/src/main/resources/application.yml
@@ -195,6 +195,7 @@
secure:
#接口放行
skip-url:
+ - /test/**
- /blade-test/**
- /blade-system/dept/selectInfo
- /blade-user/zc
--
Gitblit v1.9.3