mybatis-plus拦截器敏感字段加解密的实现方法是什么
发表于:2024-09-22 作者:千家信息网编辑
千家信息网最后更新 2024年09月22日,本篇内容主要讲解"mybatis-plus拦截器敏感字段加解密的实现方法是什么",感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习"mybatis-plus拦截器
千家信息网最后更新 2024年09月22日mybatis-plus拦截器敏感字段加解密的实现方法是什么
本篇内容主要讲解"mybatis-plus拦截器敏感字段加解密的实现方法是什么",感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习"mybatis-plus拦截器敏感字段加解密的实现方法是什么"吧!
背景
数据库在保存数据时,对于某些敏感数据需要脱敏或者加密处理,如果一个一个的去加显然工作量大而且容易出错,这个时候可以考虑使用拦截器,本文针对的是mybatis-plus作为持久层框架,其他场景未测试。代码如下:
一、查询拦截器
package com.sfpay.merchant.service.interceptor; import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;import com.sfpay.merchant.service.service.CryptService;import lombok.extern.slf4j.Slf4j;import org.apache.ibatis.binding.MapperMethod;import org.apache.ibatis.cache.CacheKey;import org.apache.ibatis.executor.Executor;import org.apache.ibatis.mapping.BoundSql;import org.apache.ibatis.mapping.MappedStatement;import org.apache.ibatis.plugin.Interceptor;import org.apache.ibatis.plugin.Intercepts;import org.apache.ibatis.plugin.Invocation;import org.apache.ibatis.plugin.Signature;import org.apache.ibatis.session.ResultHandler;import org.apache.ibatis.session.RowBounds;import org.springframework.beans.factory.annotation.Autowired; import java.util.ArrayList;import java.util.Map;import java.util.Objects; /** * @describe: 查询拦截器 * 查询条件加密使用方式:使用 @Param("decrypt")注解的自定义类型 * 返回结果解密使用方式: ①在自定义的DO上加上注解 CryptAnnotation ②在需要加解密的字段属性上加上CryptAnnotation * @author: *** * @date: 2021/3/30 17:51 */@Slf4j@Intercepts({ @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class, CacheKey.class, BoundSql.class}), @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class})})public class QueryInterceptor implements Interceptor { /** * 查询参数名称,ParamMap的key值 */ private static final String DECRYPT = "decrypt"; @Autowired private CryptService cryptService; @Autowired private UpdateInterceptor updateInterceptor; @Override public Object intercept(Invocation invocation) throws Throwable { //获取查询参数,查询条件是否需要加密 Object[] args = invocation.getArgs(); Object parameter = args[1]; Object result = null; //设置执行标识 boolean flag = true; if (parameter instanceof MapperMethod.ParamMap) { Map paramMap = (Map) parameter; if (paramMap.containsKey(DECRYPT)) { Object queryParameter = paramMap.get(DECRYPT); if (updateInterceptor.needToCrypt(queryParameter)) { //执行sql,还原加密后的报文 MappedStatement mappedStatement = (MappedStatement) args[0]; result = updateInterceptor.proceed(invocation, mappedStatement, queryParameter); flag = false; } } } //是否需要执行 if (flag) { result = invocation.proceed(); } if (Objects.isNull(result)) { return null; } // 返回列表数据,循环检查 if (result instanceof ArrayList) { ArrayList resultList = (ArrayList) result; if (CollectionUtils.isNotEmpty(resultList) && updateInterceptor.needToCrypt(resultList.get(0))) { for (Object o : resultList) { cryptService.decrypt(o); } } } else if (updateInterceptor.needToCrypt(result)) { cryptService.decrypt(result); } //返回结果 return result; }}
二、插入和更新拦截器
package com.sfpay.merchant.service.interceptor; import com.baomidou.mybatisplus.annotation.TableId;import com.sfpay.merchant.common.util.annotation.CryptAnnotation;import com.sfpay.merchant.service.service.CryptService;import org.apache.ibatis.binding.MapperMethod;import org.apache.ibatis.executor.Executor;import org.apache.ibatis.mapping.MappedStatement;import org.apache.ibatis.mapping.SqlCommandType;import org.apache.ibatis.plugin.Interceptor;import org.apache.ibatis.plugin.Intercepts;import org.apache.ibatis.plugin.Invocation;import org.apache.ibatis.plugin.Signature;import org.apache.ibatis.session.defaults.DefaultSqlSession;import org.springframework.beans.BeanUtils;import org.springframework.beans.factory.annotation.Autowired; import java.lang.reflect.Field;import java.lang.reflect.InvocationTargetException;import java.util.Arrays;import java.util.Map;import java.util.Objects;import java.util.Optional; /** * @describe: 数据库更新操作拦截器 * 一、支持的使用场景 * ①场景一:通过mybatis-plus BaseMapper自动映射的方法 * ②场景一:通过mapper接口自定义的方法,更新对象为自定义DO * 二、使用方法 * ①在自定义的DO上加上注解 CryptAnnotation * ②在需要加解密的字段属性上加上CryptAnnotation * ③自定义映射方法在需要加解密的自定义DO参数使用@Param("et") * @author: *** * @date: 2021/3/31 17:51 */@Intercepts({@Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class})})public class UpdateInterceptor implements Interceptor { @Autowired private CryptService cryptService; /** * 更新参数名称,ParamMap的key值 */ private static final String CRYPT = "et"; @Override public Object intercept(Invocation invocation) throws Throwable { //代理类方法参数,该拦截器拦截的update方法有两个参数args = {MappedStatement.class, Object.class} Object[] args = invocation.getArgs(); //获取方法参数 MappedStatement mappedStatement = (MappedStatement) args[0]; Object parameter = args[1]; if (Objects.isNull(parameter)) { //无参数,直接放行 return invocation.proceed(); } // 如果是多个参数或使用Param注解(Param注解会将参数放置在ParamMap中) if (parameter instanceof MapperMethod.ParamMap) { Map paramMap = (Map) parameter; if (paramMap.containsKey(CRYPT)) { Object updateParameter = paramMap.get(CRYPT); if (needToCrypt(updateParameter)) { //执行sql,还原加解密后的报文 return proceed(invocation, mappedStatement, updateParameter); } } } else if (parameter instanceof DefaultSqlSession.StrictMap) { //不知道是啥意思,直接过 return invocation.proceed(); } else if (needToCrypt(parameter)) { //执行sql,还原加解密后的报文 return proceed(invocation, mappedStatement, parameter); } //其他场景直接放行 return invocation.proceed(); } /** * 执行sql,还原加解密后的报文 * * @param invocation * @param mappedStatement * @param parameter * @return * @throws IllegalAccessException * @throws InstantiationException * @throws InvocationTargetException */ Object proceed(Invocation invocation, MappedStatement mappedStatement, Object parameter) throws IllegalAccessException, InstantiationException, InvocationTargetException { //先复制一个对象备份数据 Object newInstance = newInstance(parameter); //调用加解密服务 cryptService.encrypt(parameter); //执行操作,得到返回结果 Object result = invocation.proceed(); //把加解密后的字段还原 reductionParameter(mappedStatement, newInstance, parameter); //返回结果 return result; } /** * 先复制一个对象备份数据,便于加解密后还原原报文 * * @param parameter * @return * @throws IllegalAccessException * @throws InstantiationException */ private Object newInstance(Object parameter) throws IllegalAccessException, InstantiationException { Object newInstance = parameter.getClass().newInstance(); BeanUtils.copyProperties(parameter, newInstance); return newInstance; } /** * 把加解密后的字段还原,同时把mybatis返回的tableId返回给参数对象 * * @param mappedStatement * @param newInstance * @param parameter * @throws IllegalAccessException */ private void reductionParameter(MappedStatement mappedStatement, Object newInstance, Object parameter) throws IllegalAccessException { //获取映射语句命令类型 SqlCommandType sqlCommandType = mappedStatement.getSqlCommandType(); if (SqlCommandType.INSERT == sqlCommandType) { //从参数属性中找到注解是TableId的字段 Field[] parameterFields = parameter.getClass().getDeclaredFields(); Optionaloptional = Arrays.stream(parameterFields).filter(field -> field.isAnnotationPresent(TableId.class)).findAny(); if (optional.isPresent()) { Field field = optional.get(); field.setAccessible(true); Object id = field.get(parameter); //覆盖参数加解密的值 BeanUtils.copyProperties(newInstance, parameter); field.set(parameter, id); } else { //覆盖参数加解密的值 BeanUtils.copyProperties(newInstance, parameter); } } else { //覆盖参数加解密的值 BeanUtils.copyProperties(newInstance, parameter); } } /** * 是否需要加解密: * ①是否属于基本类型,void类型和String类型,如果是,不加解密 * ②DO上是否有注解 ③ 属性是否有注解 * * @param object * @return */ public boolean needToCrypt(Object object) { if (object == null) { return false; } Class> clazz = object.getClass(); if (clazz.isPrimitive() || object instanceof String) { //基本类型和字符串不加解密 return false; } //获取DO注解 boolean annotationPresent = clazz.isAnnotationPresent(CryptAnnotation.class); if (!annotationPresent) { //无DO注解不加解密 return false; } //获取属性注解 Field[] fields = clazz.getDeclaredFields(); return Arrays.stream(fields).anyMatch(field -> field.isAnnotationPresent(CryptAnnotation.class)); }}
三、注解
import com.sfpay.merchant.common.constant.EncryptDataTypeEnum; import java.lang.annotation.*; /** * @author *** * @Date 2020/12/30 20:13 * @description 加密注解类 * @Param * @return **/@Retention(RetentionPolicy.RUNTIME)@Target({ElementType.FIELD, ElementType.TYPE})@Documented@Inheritedpublic @interface CryptAnnotation { EncryptDataTypeEnum type() default EncryptDataTypeEnum.OTHER;}
cryptService 为加密服务,怎么实现自己可以根据实际情况来实现。
到此,相信大家对"mybatis-plus拦截器敏感字段加解密的实现方法是什么"有了更深的了解,不妨来实际操作一番吧!这里是网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!
参数
注解
方法
拦截器
字段
数据
查询
类型
加密
场景
属性
报文
对象
结果
更新
内容
名称
备份
实际
数据库
数据库的安全要保护哪些东西
数据库安全各自的含义是什么
生产安全数据库录入
数据库的安全性及管理
数据库安全策略包含哪些
海淀数据库安全审计系统
建立农村房屋安全信息数据库
易用的数据库客户端支持安全管理
连接数据库失败ssl安全错误
数据库的锁怎样保障安全
贵州睿蝶网络技术有限责任公司
上海方便网络技术客户至上
企业网络安全管理如何维护
pq med数据库
北京微客网络技术有限公司
宁波敏捷软件开发平台
计算机网络技术有什么推荐
德阳高层次人才数据库
盈环网络技术上海有限公司
腾讯云数据库使用
如何准备软件开发工作内容
青少年的网络安全的重要性
软件开发注册码
官渡区创新软件开发价格走势
mc服务器作弊mod
中国网络技术ipv9
质谱分子网络技术
vs登录界面调用数据库
网络安全知识竞赛200
安徽公安厅网络安全保卫总队
网络安全的最后一公里
北京做直销软件开发
计算机软件开发需要什么条件
出版行业网络安全
做原油什么软件开发
谷歌服务器怎么查看版本
梦叶草互联网科技有限公司
河南阡陌网络技术有限公司
软件开发能力怎么证明
c++ 小软件开发