大数跨境
0
0

技术专家:零代码,Spring Boot存储加密解密,支持JDBC、MyBatis及JPA

技术专家:零代码,Spring Boot存储加密解密,支持JDBC、MyBatis及JPA Spring全家桶实战案例
2025-04-05
0
导读:技术专家:零代码,Spring Boot存储加密解密,支持JDBC、MyBatis及JPA
Spring Boot 3实战案例锦集PDF电子书已更新至100篇!

🎉🎉《Spring Boot实战案例合集》目前已更新113个案例,我们将持续不断的更新。文末有电子书目录。

💪💪永久更新承诺

我们郑重承诺,所有订阅合集的粉丝都将享受永久免费的后续更新服务

💌💌如何获取
订阅我们的合集点我订阅,并通过私信联系我们,我们将第一时间将电子书发送给您。

现在就订阅合集




环境:SpringBoot3.4.2



1. 简介

存储加密的应用可以显著提高项目的数据安全性,防止数据泄露和篡改。它对于保护用户隐私、遵守法规要求以及维护企业声誉至关重要。通过实施存储加密,可以确保敏感数据在存储过程中得到最大程度的保护。

在项目开发中,我们通常会采用MyBatis、JPA或JDBC来实现数据库操作,而对于不同的持久层实现,我们需要采用相应的方案来实现数据的加解密。

  • JPA方案:使用@Converter自定义属性转换器,结合加密算法(如AES)对敏感字段加密/解密。实体类字段标注@Convert,持久化时自动加密,查询时解密。

  • MyBatis方案:通过插件(Interceptor)拦截SQL操作,对参数中的敏感数据动态加密,查询结果解密。我们也可以采用自定义的TypeHandler实现数据的处理。

  • JDBC方案:针对JDBC,我们则需要在PreparedStatement设置参数时进行数据的加密;查询时通过ResultSet对应的getXxx方法实现数据的解密。

     

本篇文章,我们将通过自定义JDBC相关的底层组件,来实现数据的自动加解密功能,从而无需在业务代码中进行任何相关的修改。

通过自定义JDBC底层的组件方案,我们可以实现数据的加解密功能,而无需特别关注具体项目中采用的是哪一种持久层框架。

首先,我们先加入下面的依赖

<dependency>  <groupId>com.github.jsqlparser</groupId>  <artifactId>jsqlparser</artifactId>  <version>5.1</version></dependency><dependency>  <groupId>com.manticore-projects.jsqlformatter</groupId>  <artifactId>jsqlformatter</artifactId>  <version>5.0</version></dependency>

我们将通过jsqlparser进行SQL解析处理。

如果你对jsqlparser还不熟悉,请查看下面这篇文章:

强大!SQL解析神器JSQLParser

2. 实战案例

2.1 自定义数据源

public class PackDataSource extends HikariDataSource {  @Override  public Connection getConnection() throws SQLException {    Connection connection = super.getConnection();    return new EncryptConnection(connection) ;  }}

为了保留Hikari数据源的强大功能,所以这里我们直接继承HikariDataSource数据源。这里为了简单起见,我们仅仅重写了父类的getConnection方法(获取数据库连接)。

配置数据源

@Configurationpublic class DataSourceConfig {  @Bean  @ConfigurationProperties(prefix = "spring.datasource.hikari")  PackDataSource dataSource(DataSourceProperties properties) {    return (PackDataSource) DataSourceBuilder.create()        .type(PackDataSource.class)        .driverClassName(properties.getDriverClassName())        .url(properties.getUrl())        .username(properties.getUsername())        .password(properties.getPassword())        .build() ;  }}

兼容默认Hikari数据源的所有配置。

2.2 自定义Connection

public class EncryptConnection extends AbstractConnection {  public EncryptConnection(Connection delegate) {    super(delegate);  }    @Override  public PreparedStatement prepareStatement(String sql) throws SQLException {    PreparedStatement statement = super.prepareStatement(sql) ;    // 解析SQL    ExecuteSqlInfo executeSqlInfo = SqlParserUtils.parse(sql) ;    return new EncryptPreparedStatement(statement, executeSqlInfo) ;  }    @Override  public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException {    PreparedStatement statement = super.prepareStatement(sql, autoGeneratedKeys) ;    // 解析SQL    ExecuteSqlInfo executeSqlInfo = SqlParserUtils.parse(sql) ;    return new EncryptPreparedStatement(statement, executeSqlInfo) ;  }    @Override  public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency)      throws SQLException {    PreparedStatement statement = super.prepareStatement(sql, resultSetType, resultSetConcurrency);    // 解析SQL    ExecuteSqlInfo executeSqlInfo = SqlParserUtils.parse(sql) ;    return new EncryptPreparedStatement(statement, executeSqlInfo) ;  }}

由于篇幅的原因,我们这里这里仅仅对部分的方法进行了重写。在获取Statement对象时,我们对当前要执行的SQL语句进行解析,主要是读取当前SQL操作什么表,有哪些字段。在下面会将该解析SQL的工具类贴出。

2.3 自定义PreparedStatement对象

public class EncryptPreparedStatement extends AbstractPreparedStatement {  private final ExecuteSqlInfo executeSqlInfo ;  public EncryptPreparedStatement(PreparedStatement delegate, ExecuteSqlInfo executeSqlInfo) {    super(delegate);    this.executeSqlInfo = executeSqlInfo ;  }    @Override  public void setString(int parameterIndex, String x) throws SQLException {    String table = executeSqlInfo.getTable() ;    List<String> columns = CryptoUtils.getEncryptProperties().getTables().get(table) ;    if (columns != null) {      ColumnInfo columnInfo = executeSqlInfo.getColumnInfo(parameterIndex) ;      if (columnInfo != null && columns.contains(columnInfo.column)) {        x = CryptoUtils.encrypt(x) ;      }    }    super.setString(parameterIndex, x);  }    @Override  public ResultSet executeQuery() throws SQLException {    ResultSet resultSet = super.executeQuery();    return new EncryptResultSet(resultSet, this.executeSqlInfo) ;  }    @Override  public ResultSet getResultSet() throws SQLException {    ResultSet resultSet = super.getResultSet();    return new EncryptResultSet(resultSet, this.executeSqlInfo) ;  }}

在该类中我们也仅仅是重写了部分核心的方法。如下方法说明:

  • setString:该方法中我们将会对哪些需要加密的列进行加密处理

【声明】内容源于网络
0
0
Spring全家桶实战案例
Java全栈开发,前端Vue2/3全家桶;Spring, SpringBoot 2/3, Spring Cloud各种实战案例及源码解读
内容 832
粉丝 0
Spring全家桶实战案例 Java全栈开发,前端Vue2/3全家桶;Spring, SpringBoot 2/3, Spring Cloud各种实战案例及源码解读
总阅读38
粉丝0
内容832