Spring Boot使用Jasypt加密MongoDB URI配置认证失败问题排查
Hey there, let's break down why your Jasypt-encrypted password isn't working with the MongoDB URI configuration and how to fix it:
The Problem
You're using Spring Boot 1.5.2, Jasypt 1.14, and MongoDB 3.4.2. When passing config via SPRING_APPLICATION_JSON, using the combined spring.data.mongodb.uri results in authentication failures because the encrypted ENC(...) password isn't being decrypted (it shows up raw in logs). But when you split the config into separate host, port, username, and password properties, everything works fine.
Why This Happens
In Spring Boot 1.x, the spring.data.mongodb.uri property takes priority over individual MongoDB configs. Here's the catch: Jasypt decrypts individual properties during Spring's environment initialization, but when you use a placeholder like ${spring.data.mongodb.password} inside the URI, Spring only replaces the placeholder with the raw ENC(...) string—it doesn't trigger a second decryption pass for the value inside the URI. The MongoDB driver ends up trying to authenticate with the encrypted string as the password, hence the MongoSecurityException.
Solutions to Try
1. Custom Decryption for the MongoDB URI
You can manually decrypt the password within the URI by creating a custom configuration bean:
- First, update your JSON config to put the encrypted password directly in the URI:
{ "spring": { "data": { "mongodb": { "uri": "mongodb://myusername:ENC(Qev1vJ3DummyPSUApeQfgdgfd==)@localhost:27017/mydb" } } }, "jasypt": { "encryptor": { "password": "myjasypt-password" } } }
- Then add this configuration class to handle decryption:
import org.jasypt.encryption.StringEncryptor; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.mongo.MongoProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.mongodb.MongoDbFactory; import org.springframework.data.mongodb.core.MongoTemplate; import org.springframework.data.mongodb.core.SimpleMongoDbFactory; import com.mongodb.MongoClientURI; @Configuration public class CustomMongoConfig { @Autowired private StringEncryptor jasyptStringEncryptor; @Autowired private MongoProperties mongoProps; @Bean public MongoDbFactory mongoDbFactory() throws Exception { String rawUri = mongoProps.getUri(); // Decrypt the ENC(...) part in the URI String decryptedUri = rawUri.replaceAll("ENC\\(([^)]+)\\)", matcher -> jasyptStringEncryptor.decrypt(matcher.group(1)) ); return new SimpleMongoDbFactory(new MongoClientURI(decryptedUri)); } @Bean public MongoTemplate mongoTemplate() throws Exception { return new MongoTemplate(mongoDbFactory()); } }
This bean intercepts the raw URI, decrypts the password segment using Jasypt's encryptor, and passes the cleaned URI to the MongoDB factory.
2. Upgrade Spring Boot (Recommended)
Spring Boot 2.x completely revamped external configuration handling, and Jasypt integration works seamlessly with MongoDB URIs out of the box. If your project can tolerate an upgrade, moving to Spring Boot 2.x (pair with Jasypt 2.1.0+ for compatibility) will eliminate this issue without custom code.
3. Use Environment Variables (Quick, Not Ideal for Production)
If you need a quick fix without code changes, you can decrypt the password first and pass it as an environment variable:
- Use Jasypt's command-line tool to decrypt the password, then inject it into the URI:
# Decrypt the password and pass it as an env var java -DMONGO_PWD=$(jasypt-decrypt --input "Qev1vJ3DummyPSUApeQfgdgfd==" --password "myjasypt-password") \ -Dspring.application.json='{"spring":{"data":{"mongodb":{"uri":"mongodb://myusername:${MONGO_PWD}@localhost:27017/mydb"}}}}' \ -jar myapp.jar
Note: This exposes the plaintext password in the process list, so avoid this in production environments.
How to Verify
After implementing a fix, you can add a quick log statement in your config class (masking the password!) to confirm the URI is decrypted correctly, or check the MongoDB driver logs to ensure the authentication uses the plaintext password.
内容的提问来源于stack exchange,提问作者Haran

