详解MybatisPlus数据安全

news2025/8/12 3:57:58

MybatisPlus数据安全

概述

​ 存在数据库中的数据对于普通用户而言是不可见的,好像是藏起来了一样,但对于开发者,只要知道数据库的连接地址、用户名、密码,则数据不再安全;这也意味着,一旦连接数据库的配置文件暴露出去,则数据不再安全。

应用场景

开发中的数据库配置文件或配置中心中的配置信息

API介绍

MybatisPlus中有个针对配置项加密处理的

在这里插入图片描述

在这里插入图片描述

代码实现

1 创建mp工程

创建maven工程,结构如下:

在这里插入图片描述

2 代码编写

pom.xml

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.4.1</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <scope>provided</scope>
        </dependency>
    </dependencies>

application.yml

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/springboot?useSSL=false&characterEncoding=utf8&serverTimezone=Asia/Shanghai
    driver-class-name: com.mysql.cj.jdbc.Driver
    username: root
    password: root
mybatis-plus:
  type-aliases-package: com.itheima.pojo

启动类

package com.itheima;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * @version 1.0
 * @description 说明
 * @package com.itheima
 */
@SpringBootApplication
@MapperScan(basePackages = "com.itheima.mapper")
public class App {
    public static void main(String[] args) {
        SpringApplication.run(App.class,args);
    }
}

pojo

package com.itheima.pojo;

import com.baomidou.mybatisplus.annotation.TableField;
import lombok.Data;

/**
 * @version 1.0
 * @description 说明
 * @package com.itheima.pojo
 */
@Data
public class User {
    private Integer id;
    private String username;
    @TableField(select = false)
    private String password;
    private String salt;

}

mapper

package com.itheima.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.itheima.pojo.User;
import org.springframework.stereotype.Repository;

/**
 * @version 1.0
 * @description 说明
 * @package com.itheima.mapper
 */
@Repository
public interface UserMapper extends BaseMapper<User> {
}

service接口与实现类

package com.itheima.service;

import com.baomidou.mybatisplus.extension.service.IService;
import com.itheima.pojo.User;

/**
 * @version 1.0
 * @description 说明
 * @package com.itheima.service
 */
public interface UserService extends IService<User> {
}

package com.itheima.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.itheima.mapper.UserMapper;
import com.itheima.pojo.User;
import com.itheima.service.UserService;
import org.springframework.stereotype.Service;

/**
 * @version 1.0
 * @description 说明
 * @package com.itheima.service.impl
 */
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
}

controller

package com.itheima.controller;

import com.itheima.pojo.User;
import com.itheima.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

/**
 * @version 1.0
 * @description 说明
 * @package com.itheima.controller
 */
@RestController
@RequestMapping("user")
public class UserController {

    @Autowired
    private UserService userService;

    @GetMapping
    public List<User> listAll(){
        return userService.list();
    }

}

启动测试

生成加密后的内容
package com.itheima;

import com.baomidou.mybatisplus.core.toolkit.AES;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * @version 1.0
 * @description 说明
 * @package com.itheima
 */
@SpringBootApplication
@MapperScan(basePackages = "com.itheima.mapper")
public class App {
    public static void main(String[] args) {
        String secretKey = AES.generateRandomKey();
        System.out.println("secretKey:" + secretKey);

        String url = AES.encrypt("jdbc:mysql://localhost:3306/springboot?useSSL=false&characterEncoding=utf8&serverTimezone=Asia/Shanghai", secretKey);
        String username = AES.encrypt("username", secretKey);
        String password = AES.encrypt("password", secretKey);
        System.out.println("url=" +url );
        System.out.println("username=" +username );
        System.out.println("password=" +password );

        SpringApplication.run(App.class,args);
    }
}

在这里插入图片描述

替换配置文件
spring:
  datasource:
    url: mpw:wT9PqZ9Hf4VWgXDuZ/Z1JKfdDyS0sSu3+O2qDkJ/Ulnabpq3z1lZbiThWseQ4DQSx3+SWpufsTysjdYhn6Scsa77AzIIaUgv8DZ17gPxAq88AISmxd9OjxidmY50uBVMkGhP9qAted45zuHBzVrw6Q==
    driver-class-name: com.mysql.cj.jdbc.Driver
    username: mpw:Pnh++mI45YrC4s6JveJYaA==
    password: mpw:Pnh++mI45YrC4s6JveJYaA==
mybatis-plus:
  type-aliases-package: com.itheima.pojo
添加启动参数

在这里插入图片描述

运行效果

在这里插入图片描述

3 优化

目的

启动时,需要指定密钥 才能使用,如果我们把它封装到一个jar里,让它启动时自动去加载密钥,且密钥可配置,那这样就更灵活了。

分析

通过查看MybatisPlus加载的源码,其做解密处理的类如下:

/*
 * Copyright (c) 2011-2020, baomidou (jobob@qq.com).
 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 * <p>
 * https://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package com.baomidou.mybatisplus.autoconfigure;

import com.baomidou.mybatisplus.core.toolkit.AES;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.env.EnvironmentPostProcessor;
import org.springframework.boot.env.OriginTrackedMapPropertySource;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.MapPropertySource;
import org.springframework.core.env.PropertySource;
import org.springframework.core.env.SimpleCommandLinePropertySource;

import java.util.HashMap;

/**
 * 安全加密处理器
 *
 * @author hubin
 * @since 2020-05-23
 */
public class SafetyEncryptProcessor implements EnvironmentPostProcessor {

    @Override
    public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
        /**
         * 命令行中获取密钥
         */
        String mpwKey = null;
        for (PropertySource<?> ps : environment.getPropertySources()) {
            if (ps instanceof SimpleCommandLinePropertySource) {
                SimpleCommandLinePropertySource source = (SimpleCommandLinePropertySource) ps;
                mpwKey = source.getProperty("mpw.key");
                break;
            }
        }
        /**
         * 处理加密内容
         */
        if (StringUtils.isNotBlank(mpwKey)) {
            HashMap<String, Object> map = new HashMap<>();
            for (PropertySource<?> ps : environment.getPropertySources()) {
                if (ps instanceof OriginTrackedMapPropertySource) {
                    OriginTrackedMapPropertySource source = (OriginTrackedMapPropertySource) ps;
                    for (String name : source.getPropertyNames()) {
                        Object value = source.getProperty(name);
                        if (value instanceof String) {
                            String str = (String) value;
                            if (str.startsWith("mpw:")) {
                                map.put(name, AES.decrypt(str.substring(4), mpwKey));
                            }
                        }
                    }
                }
            }
            // 将解密的数据放入环境变量,并处于第一优先级上
            if (CollectionUtils.isNotEmpty(map)) {
                environment.getPropertySources().addFirst(new MapPropertySource("custom-encrypt", map));
            }
        }
    }
}

其使用了SPI原理,在类所在的jar下的META-INF/spring.factories中配置了这个SafetyEncryptProcessor。那我们能否也来定义一个这样的配置处理器,判断环境配置中是否配置了–mpw.key,如果没有配置,则给它配置上,这样就不用在启动时添加参数来运行了。

实现

创建配置工程mysafe

在这里插入图片描述

代码清单

pom.xml

<parent>
    <artifactId>spring-boot-starter-parent</artifactId>
    <groupId>org.springframework.boot</groupId>
    <version>2.3.8.RELEASE</version>
</parent>
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter</artifactId>
    </dependency>
</dependencies>

SafetyEncryptProcessor

package com.itheima;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.env.EnvironmentPostProcessor;
import org.springframework.core.Ordered;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.PropertySource;
import org.springframework.core.env.SimpleCommandLinePropertySource;
import org.springframework.core.io.ClassPathResource;
import org.springframework.util.StringUtils;

import java.io.IOException;
import java.util.Properties;

/**
 * @version 1.0
 * @description 说明
 * @package com.itheima
 */
public class SafetyEncryptProcessor implements EnvironmentPostProcessor, Ordered {

    @Override
    public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
        Properties pro = new Properties();
        try {
            pro.load(new ClassPathResource("ert.properties").getInputStream());
        } catch (IOException e) {
            e.printStackTrace();
        }
        /**
         * 命令行中获取密钥
         */
        String mpwKey = null;
        for (PropertySource<?> ps : environment.getPropertySources()) {
            if (ps instanceof SimpleCommandLinePropertySource) {
                SimpleCommandLinePropertySource source = (SimpleCommandLinePropertySource) ps;
                mpwKey = source.getProperty("mpw.key");
                break;
            }
        }
        if(StringUtils.isEmpty(mpwKey)){
            environment.getPropertySources().addFirst(new SimpleCommandLinePropertySource("mySpringApplicationCommandLineArgs", "--mpw.key=" + pro.getProperty("ert.version")));
        }
    }

    @Override
    public int getOrder() {
        return 0;
    }
}

spring.factories

ert.version=b440fe7fd55dbe26
org.springframework.boot.env.EnvironmentPostProcessor=\
com.itheima.SafetyEncryptProcessor

ert.properties

ert.version=2ac6625cb3188f52
安装到本地仓库

在这里插入图片描述

修改mp工程添加依赖

修改pom.xml,添加mysafe的依赖

<dependency>
    <groupId>com.itheima</groupId>
    <artifactId>mysafe</artifactId>
    <version>1.0-SNAPSHOT</version>
</dependency>

4 测试结果

去除启动时的参数设置。再启动后访问页面、效果如下:

在这里插入图片描述

总结

  1. MybatisPlus利用了springboot的配置信息增强器与SPI机制来实现对配置文件中敏感数据的解密处理。

  2. mysafe工程打成的jar包,将来就上传到企业的内部服务器上,当密钥变更时,重新打包即可。

  3. 而我们将来布署项目到服务器上时,也肯定存在配置文件,一旦配置信息暴露,则数据库就危险了。通过加密手段能够让破解者增加破解阻碍。

  4. 此次练习仅做抛砖引玉作用,关于加密与解密是没有做到那么严谨的,需要结合自己公司实际情况去调整。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/15248.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

卡塔尔世界杯倒计时!世界杯直播在哪里观看?美家市场汇总来了!

来了来了&#xff0c;2022卡塔尔世界杯倒计时3天&#xff01;2022卡塔尔世界杯将在北京时间11月21日开始&#xff0c;持续时间28天&#xff0c;至2022年12月18日结束&#xff0c;将近一个月的赛程让众多球迷们期待不已&#xff0c;这一个月将是全世界球迷们最快乐的一个月&…

【网站架构】如何长久运行升级?高可用部署只是基础,巡检、监控、应用数据备份、日志、灰度发布

大家好&#xff0c;欢迎来到停止重构的频道。本期讨论大型网站的可用性。 高可用指的是当一部分服务器宕机时&#xff0c;网站系统仍可正常运行。 一些常用的软件服务的高可用部署方案 &#xff0c;如Tomcat、Nginx、Redis、MySQL等&#xff0c;在往期性能调优时已经有详细的介…

H5组件Canvas画电子印章

效果图 代码 <!DOCTYPE html> <html> <head> <meta charset"UTF-8"> <title>HTML5 Canvas印章</title> <script type"text/javascript" src"https://code.jquery.com/jquery-2.2.4.js"></scri…

电科大离散数学-4-二元关系

目录 4.1 序偶和笛卡尔积 4.1.1 有序组的定义 4.1.2 笛卡儿积 4.1.3 笛卡儿积的性质 4.1.4 推广 4.2 关系的定义 4.2.1 二元关系的定义 4.2.2 二元关系的数学符号 4.2.3 枚举二元关系 4.2.4 几种重要关系 4.2.5 定义域和值域 4.2.6 n元关系 4.3 关系的表示 4.3.1…

[附源码]SSM计算机毕业设计中小型艺术培训机构管理系统JAVA

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

List<Map<String, Object>>,Map<String,List<Map<String, Object>>>多方式循环遍历

多方式循环遍历1. List<Map<String, Object>>多方式循环测试结果2. Map&#xff1c;String,List&#xff1c;Map&#xff1c;String, Object&#xff1e;&#xff1e;&#xff1e;测试结果☀️相关笔记章节&#xff1a; &#x1f339;java 1.8 stream使用总结&…

MySQL8.0优化 - 优化MySQL服务器、优化MySQL的参数、优化数据类型

文章目录学习资料优化MySQL服务器优化服务器硬件配置较大的内存配置高速磁盘系统合理分布磁盘I/O配置多处理器优化MySQL的参数innodb_buffer_pool_sizekey_buffer_sizetable_cachequery_cache_sizequery_cache_typesort_buffer_sizejoin_buffer_sizeread_buffer_sizeinnodb_flu…

RabbitMQ初步到精通-第四章-RabbitMQ工作模式-SIMPLE

RabbitMQ工作模式-SIMPLE模式 1.模式介绍 这是最简单的一个模式了&#xff0c;一般在实际的生产环境中&#xff0c;大家应该都不会使用一个消费者。只做入门的介绍。 一个生产者&#xff0c;一个默认的交换机【图中没体现】&#xff0c;一个队列&#xff0c;一个消费者。 生产…

【Java技术专题】「Java8技术盲区」函数接口字典-看看还有哪些你所不知道函数接口

函数接口的定义 函数式接口(Functional Interface)就是一个有且仅有一个抽象方法&#xff0c;但是可以有多个非抽象方法的接口。 函数接口的特点 函数式接口可以被隐式转换为lambda表达式。 Lambda表达式和方法引用&#xff08;实际上也可认为是Lambda表达式&#xff09;上。 …

子序列宽度之和

目录题目1. 子序列2. 子序列找最大最小值3. 代码题目 一个序列的 宽度 定义为该序列中最大元素和最小元素的差值。 给你一个整数数组 nums &#xff0c;返回 nums 的所有非空 子序列 的 宽度之和 。由于答案可能非常大&#xff0c;请返回对 109 7 取余 后的结果。 子序列 定义…

[附源码]java毕业设计农业种植管理系统

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

IDEA中给源码添加自己注释——private-notes插件安装使用

一、前言 我们在空闲之余喜欢研究一些经典框架的源码&#xff0c;发现没办法把自己的注释添加上。 会给出提示&#xff1a;File is read-only 很烦&#xff0c;但是为了安全考虑也是没有办法的&#xff01; 这是一个大佬就写了一个IDEA插件&#xff0c;让我们摆脱了这个烦恼&a…

U2-Net 使用嵌套 U 结构进行更深入的显着目标检测

在给定图像中分割不同的对象一直是计算机视觉领域的一项众所周知的任务。多年来,我们已经看到自编码器到疯狂的深度学习模型(如 Deeplab)被用于语义分割。在所有模型的深海中,仍然有一个名字排在最前面,它就是U-Net。U-Net 于 2018 年发布,此后获得了巨大的普及,并以某种…

Android入门第30天-Android里的Toast的使用

介绍 本篇带来的是&#xff1a; Android用于提示信息的一个控件——Toast(吐司)&#xff01;Toast是一种很方便的消息提示框,会在 屏幕中显示一个消息提示框,没任何按钮,也不会获得焦点一段时间过后自动消失&#xff01; 非常常用&#xff01;我们通过一个例子把Toast的使用讲…

【重识云原生】第六章容器基础6.4.9.6节——Service 与 Pod 的DNS

1 Service 与 Pod 的 DNS Kubernetes 为 Service 和 Pod 创建 DNS 记录。 你可以使用一致的 DNS 名称而非 IP 地址访问 Service。 Kubernetes DNS 除了在集群上调度 DNS Pod 和 Service&#xff0c; 还配置 kubelet 以告知各个容器使用 DNS Service 的 IP 来解析 DNS 名称。 集…

bcn_timout,ap_probe_send_start

ESP32 使用 beacon 超时机制检测 AP 是否活跃。如果 station 在 inactive 时间内未收到所连接 AP 的 beacon&#xff0c;将发生 beacon 超时。inactive 时间通过调用函数 esp_wifi_set_inactive_time() 设置。 beacon 超时发生后&#xff0c;station 将向 AP 发送 5 个 probe …

智芯传感MEMS压力传感器促进无人机跨入极其广阔的应用市场

2022年11月8日至13日&#xff0c;第十四届中国国际航空航天博览会在广东珠海国际航展中心举办。伴随着人工智能技术的进步&#xff0c;全球无人化装备的发展如火如荼。各式各样的无人机在无人化装备中可谓是一枝独秀&#xff0c;广受外界的高度关注。 据美国《Aviation Week&am…

【元宇宙欧米说】从GameFi的视角讨论Web2到Web3的利弊

什么将会是Web3生态赛道发展的未来&#xff1f;争议很大的GameFi如何建立高价值的商业生态&#xff1f; 11月23日下午三点&#xff0c;IDV合作经理Chillax将以“从GameFi视角讨论Web2到Web3的利弊”为题&#xff0c;与大家共同探讨Web3时代的到来如何影响GameFi的发展。 Bloc…

web自动化测试入门篇03——selenium使用教程

&#x1f60f;作者简介&#xff1a;博主是一位测试管理者&#xff0c;同时也是一名对外企业兼职讲师。 &#x1f4e1;主页地址&#xff1a;【Austin_zhai】 &#x1f646;目的与景愿&#xff1a;旨在于能帮助更多的测试行业人员提升软硬技能&#xff0c;分享行业相关最新信息。…

C++ Reference: Standard C++ Library reference: Containers: deque: deque: insert

C官网参考链接&#xff1a;https://cplusplus.com/reference/deque/deque/insert/ 公有成员函数 <deque> std::deque::insert C98 单个元素 (1) iterator insert (iterator position, const value_type& val); 填充 (2) void insert (iterator position, s…