简体   繁体   English

如何配置带有身份验证的嵌入式MongoDB,以用于Spring Boot集成测试?

[英]How do I configure embedded MongoDB with authentication for use in spring boot integration tests?

I have a spring boot application that is using MongoDB for persistence. 我有一个使用MongoDB进行持久化的Spring Boot应用程序。 I'm putting together integration tests, and I'm using the flapdoodle embedded mongo library for the embedded DB. 我正在进行集成测试,并且正在为嵌入式DB使用flappoodle嵌入式mongo库。

This is coupled with spring boots auto-configure and everything works wonderfully for integration tests. 这与弹簧靴的自动配置结合在一起,对于集成测试而言,一切工作都非常出色。 As soon as I add authentication credentials for MongoDB, however, everything falls apart. 但是,一旦我添加了MongoDB的身份验证凭据,一切都会崩溃。

My understanding is that spring auto-configure finds the credentials and attempts to connect to the database with authentication, which fails, because it's an embedded database that hasn't been initialized with credentials yet. 我的理解是,spring自动配置会找到凭据并尝试通过身份验证连接到数据库,但失败了,因为它是一个尚未使用凭据初始化的嵌入式数据库。

I've attempted to use mongeez in order to initialize the credentials pre-spring startup, but this library has the same issue with credentials sensing. 我尝试使用mongeez来在春季启动前初始化凭据,但是该库在凭据感知方面存在相同的问题。

So my real question: 所以我真正的问题是:

Is there a way to initialize the embedded database with authentication? 有没有办法通过身份验证来初始化嵌入式数据库? I've been digging through the source code and haven't found anything. 我一直在研究源代码,但没有发现任何东西。

I had the same issue. 我遇到过同样的问题。 This is how it works for me (using Kotlin): 这是对我有效的方式(使用Kotlin):

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, properties = ["spring.data.mongodb.port="])
class IntegrationTests {

@Autowired
private val webClient: WebTestClient? = null

@Autowired
private val mongoConfig: IMongodConfig? = null
var collection: MongoCollection<Document>? = null

fun createDBAndCollection(collectionName: String){
    val mongo = MongoClient("127.0.0.1", mongoConfig!!.net().port)
    val db = mongo.getDatabase("local")
    db.createCollection(collectionName)
    collection = db.getCollection(collectionName)
}

@Test
fun `Find all tracks on JSON REST endpoint`() {
    createDBAndCollection("track")
    collection?.insertOne(Document("key", "val"))

    webClient!!.get().uri("/reactive/tracks")
            .accept(APPLICATION_JSON)
            .exchange()
            .expectStatus().is2xxSuccessful
            .expectBodyList<Track>()
            .hasSize(1);
}
}
  • No need to change application.properties. 无需更改application.properties。 Its enough to empty the port setting using the SprintBootTest Annotation (other approaches did not work for me, like eg @TestPropertySource) 它足以使用SprintBootTest Annotation清空端口设置(其他方法对我不起作用,例如@TestPropertySource)
  • mongoConfig is injected and used to retrieve the random port generated by flapdoodle mongoConfig被注入并用于检索由flappoodle生成的随机端口
  • the database name must match the one in application.properties (I am sure there is a way to read this dynamically at runtime though). 数据库名称必须与application.properties中的名称匹配(不过我敢肯定有一种方法可以在运行时动态读取它)。

My gradle test dependencies are: 我的gradle测试依赖项是:

testImplementation('de.flapdoodle.embed:de.flapdoodle.embed.mongo')
testImplementation('io.projectreactor:reactor-test')
testImplementation('org.springframework.boot:spring-boot-starter-test')
testImplementation("org.junit.jupiter:junit-jupiter-api")
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine")

Actually you can create an authenticated user by looking at you admin.system.users collection. 实际上,您可以通过查看admin.system.users集合来创建经过身份验证的用户。 Just create a test user and put it there with the mongo client. 只需创建一个测试用户并将其与mongo客户端放在一起即可。 As soon as you have a user there you can dump that document and use that json to create a new authenticated user in your embedded mongo test suite. 一旦有了用户,您就可以转储该文档,并使用该json在嵌入式mongo测试套件中创建经过身份验证的新用户。 It would be something like this: 就像这样:

private static void createAuthorizationUser() {
    MongoClient mongoClient = new MongoClient(HOST);
    MongoDatabase admin = mongoClient.getDatabase("admin");
    MongoCollection<Document> usersCollection = admin.getCollection("system.users");
    usersCollection.insertOne(Document.parse(""
            + "{\n" + 
            "    \"_id\": \"admin.test-user\",\n" + 
            //"    \"userId\": Binary(\"rT2Ig**********jGXZEQ==\", 4),\n" + 
            "    \"user\": \"test-user\",\n" + 
            "    \"db\": \"admin\",\n" + 
            "    \"credentials\": {\n" + 
            "        \"SCRAM-SHA-1\": {\n" + 
            "            \"iterationCount\": 10000,\n" + 
            "            \"salt\": \"gmm******GnNcAw==\",\n" + 
            "            \"storedKey\": \"qE***********8/LAvG7s=\",\n" + 
            "            \"serverKey\": \"Re*********eQh6w=\"\n" + 
            "        }\n" + 
            "    },\n" + 
            "    \"roles\": [\n" + 
            "        {\n" + 
            "            \"role\": \"readWrite\",\n" + 
            "            \"db\": \"test\"\n" + 
            "        }\n" + 
            "    ]\n" + 
            "}"
            + ""));
}

I've created a user named test-user that has readWrite privileges over test db. 我创建了一个名为test-user的用户,该用户对test db具有readWrite特权。 For some reason the embedded Mongo does not like the Binary function, but just commenting it does not hurt the authentication feature. 出于某种原因,嵌入式Mongo不喜欢Binary函数,而只是对其进行注释不会损害身份验证功能。

When creating a client you can do simply through 创建客户时,您可以简单地通过

MongoClient mongoClient = new MongoClient(
    new MongoClientURI( 
        String.format("mongodb://%s:%s@%s:%d/%s", "test-user", "****", "localhost", 27017, "admin" ) 
    )
);

It should fix the problem. 它应该解决问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM