You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Data Mongo自定义类显式加密读取失败问题

Spring Boot MongoDB 自定义类字段显式加密解密异常修复

问题原因

MongoEncryptionConverter 默认仅处理基础Bson类型(如字符串、整数对应的BsonString、BsonInt32)。当加密自定义类或其列表时,写入前对象会被序列化为Document,但解密逻辑错误地尝试将Document直接转换为BsonValue,触发类型转换异常。

修复方案

1. 实现自定义加密转换器

扩展MongoEncryptionConverter,先将复杂类型序列化为BsonDocument再加密,解密后再反序列化为目标类型:

class CustomMongoEncryptionConverter(
    encryption: MongoClientEncryption,
    keyResolver: EncryptionKeyResolver,
    private val mappingConverter: MappingMongoConverter
) : MongoEncryptionConverter(encryption, keyResolver) {

    override fun read(source: Any, type: TypeDescriptor): Any? {
        if (source is BsonBinary && source.type == BsonBinaryType.ENCRYPTED) {
            val decrypted = super.read(source, type)
            // 解密后若为BsonDocument,反序列化为目标类型
            return if (decrypted is BsonDocument && !isSimpleType(type.type)) {
                mappingConverter.read(type.type as Class<*>, decrypted)
            } else {
                decrypted
            }
        }
        return super.read(source, type)
    }

    override fun write(source: Any?, type: TypeDescriptor): Any? {
        val bsonValue = source?.takeIf { !isSimpleType(it.javaClass) }
            ?.let { mappingConverter.write(it) }
            ?: super.write(source, type)
        return super.write(bsonValue, type)
    }

    private fun isSimpleType(clazz: Class<*>): Boolean {
        return clazz.isPrimitive || clazz.isAssignableFrom(String::class.java) || Number::class.java.isAssignableFrom(clazz)
    }
}

2. 更新Mongo配置,使用自定义转换器

在MongoConfig中注入MappingMongoConverter,替换默认的加密转换器:

@Configuration
class MongoConfig(
    private val clientEncryption: ClientEncryption,
    private val masterKeyProvider: MasterKeyProvider,
    private val appContext: ApplicationContext,
    private val mappingMongoConverter: MappingMongoConverter // 新增注入
) : AbstractMongoClientConfiguration() {

    // 原有静态常量、mongoClient方法保持不变
    companion object {
        val vaultCollectionName = "__keyVault"
        val dbName = "dbName"
        val keyVaultNamespace = "$dbName.$vaultCollectionName"
        val connectionString = ConnectionString("dummy-connection-string")
    }

    override fun mongoClient(): MongoClient {
        val autoEncryptionSettings = AutoEncryptionSettings.builder()
            .keyVaultNamespace(keyVaultNamespace)
            .kmsProviders(masterKeyProvider.kmsProviders())
            .bypassAutoEncryption(true)
            .build()

        return MongoClients.create(
            MongoClientSettings.builder()
                .applyConnectionString(connectionString)
                .autoEncryptionSettings(autoEncryptionSettings)
                .build()
        )
    }

    @Bean
    fun encryptingConverter(): MongoEncryptionConverter {
        val encryption = MongoClientEncryption.just(clientEncryption)
        val keyResolver = EncryptionKeyResolver.annotated { _ -> EncryptionKey.keyAltName("demo-data-key") }
        return CustomMongoEncryptionConverter(encryption, keyResolver, mappingMongoConverter)
    }

    override fun configureConverters(converterConfigurationAdapter: MongoCustomConversions.MongoConverterConfigurationAdapter) {
        converterConfigurationAdapter.registerPropertyValueConverterFactory(PropertyValueConverterFactory.beanFactoryAware(appContext))
    }

    override fun getDatabaseName(): String {
        return "databaseName"
    }
}

3. 确保自定义类的映射配置

自定义类需被Spring Data MongoDB正确识别,嵌套类无需@Document,但需保证字段可被映射:

// 嵌套自定义类
data class UserProfile(
    val fullName: String,
    val phone: String
)

// 主实体
@Document(collection = "customers")
data class Customer(
    @Id val id: String?,
    @ExplicitEncrypted val profile: UserProfile, // 加密自定义类
    @ExplicitEncrypted val pastProfiles: List<UserProfile> // 加密自定义类列表
)

4. 版本兼容性确认

当前使用的Spring Boot 3.1.1(对应Spring Data MongoDB 4.1.1)与mongodb-crypt 1.8.0版本兼容,无需调整依赖版本。

验证步骤

  1. 插入包含自定义类字段的实体,通过MongoDB Compass确认数据为加密的BinData(6, ...)格式
  2. 读取实体,检查是否无类型转换异常,且自定义类字段值正确

内容的提问来源于stack exchange,提问作者Christian

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 12:52:53