【问题标题】:Attempt to switch database target during SASL authentication在 SASL 身份验证期间尝试切换数据库目标
【发布时间】:2021-04-14 05:15:52
【问题描述】:

我尝试在 Spring Boot 项目中设置 Mongo DB。我在 application.yml 中设置了一个 uri:

spring:
  data:
    mongodb:
      uri: mongodb://user:pass@localhost:27017/mydbname

但应用程序无法从存储库中读取数据并出现错误:

Attempt to switch database target during SASL authentication.

发生错误的行(kotlin):

val emails = emailRepository.findAllByStatus(READY_TO_SEND)

在哪里

interface EmailRepository : MongoRepository<Email, String> {
    fun findAllByStatus(status: EmailStatus) : Collection<Email>
}

data class Email(
    @Id
    @get:JsonIgnore
    var id: String? = null,
    @get:NotNull
    val from: MailActor,
    @get:NotEmpty
    val to: Collection<MailActor>,
    @get:NotEmpty
    val subject: String,
    @get:NotEmpty
    val htmlText: String,
    val attachments: Collection<Attachment> = listOf(),
    val cc: Collection<MailActor> = listOf(),
    val bcc: Collection<MailActor> = listOf(),
    @get:JsonIgnore
    val status: EmailStatus = EmailStatus.READY_TO_SEND,
    @get:JsonIgnore
    val created: LocalDateTime = LocalDateTime.now(),
    @get:JsonIgnore
    val lastSendAttempt: LocalDateTime? = null,
)

在存储库上的findAllsave 操作也会发生同样的错误(可能还有其他错误)

堆栈跟踪:

Caused by: com.mongodb.MongoSecurityException: Exception authenticating MongoCredential{mechanism=SCRAM-SHA-1, userName='user', source='user', password=<hidden>, mechanismProperties=<hidden>}
    at com.mongodb.internal.connection.SaslAuthenticator.wrapException(SaslAuthenticator.java:235) ~[mongodb-driver-core-4.1.1.jar:na]
    at com.mongodb.internal.connection.SaslAuthenticator$1.run(SaslAuthenticator.java:80) ~[mongodb-driver-core-4.1.1.jar:na]
    at com.mongodb.internal.connection.SaslAuthenticator$1.run(SaslAuthenticator.java:51) ~[mongodb-driver-core-4.1.1.jar:na]
    at com.mongodb.internal.connection.SaslAuthenticator.doAsSubject(SaslAuthenticator.java:241) ~[mongodb-driver-core-4.1.1.jar:na]
    at com.mongodb.internal.connection.SaslAuthenticator.authenticate(SaslAuthenticator.java:51) ~[mongodb-driver-core-4.1.1.jar:na]
    at com.mongodb.internal.connection.InternalStreamConnectionInitializer.authenticate(InternalStreamConnectionInitializer.java:168) ~[mongodb-driver-core-4.1.1.jar:na]
    at com.mongodb.internal.connection.InternalStreamConnectionInitializer.initialize(InternalStreamConnectionInitializer.java:63) ~[mongodb-driver-core-4.1.1.jar:na]
    at com.mongodb.internal.connection.InternalStreamConnection.open(InternalStreamConnection.java:144) ~[mongodb-driver-core-4.1.1.jar:na]
    at com.mongodb.internal.connection.UsageTrackingInternalConnection.open(UsageTrackingInternalConnection.java:51) ~[mongodb-driver-core-4.1.1.jar:na]
    at com.mongodb.internal.connection.DefaultConnectionPool$PooledConnection.open(DefaultConnectionPool.java:431) ~[mongodb-driver-core-4.1.1.jar:na]
    at com.mongodb.internal.connection.DefaultConnectionPool.get(DefaultConnectionPool.java:115) ~[mongodb-driver-core-4.1.1.jar:na]
    at com.mongodb.internal.connection.DefaultConnectionPool.get(DefaultConnectionPool.java:100) ~[mongodb-driver-core-4.1.1.jar:na]
    at com.mongodb.internal.connection.DefaultServer.getConnection(DefaultServer.java:92) ~[mongodb-driver-core-4.1.1.jar:na]
    at com.mongodb.internal.binding.ClusterBinding$ClusterBindingConnectionSource.getConnection(ClusterBinding.java:119) ~[mongodb-driver-core-4.1.1.jar:na]
    at com.mongodb.client.internal.ClientSessionBinding$SessionBindingConnectionSource.getConnection(ClientSessionBinding.java:135) ~[mongodb-driver-sync-4.1.1.jar:na]
    at com.mongodb.internal.operation.FindOperation$1.call(FindOperation.java:653) ~[mongodb-driver-core-4.1.1.jar:na]
    at com.mongodb.internal.operation.FindOperation$1.call(FindOperation.java:650) ~[mongodb-driver-core-4.1.1.jar:na]
    at com.mongodb.internal.operation.OperationHelper.withReadConnectionSource(OperationHelper.java:582) ~[mongodb-driver-core-4.1.1.jar:na]
    at com.mongodb.internal.operation.FindOperation.execute(FindOperation.java:650) ~[mongodb-driver-core-4.1.1.jar:na]
    at com.mongodb.internal.operation.FindOperation.execute(FindOperation.java:78) ~[mongodb-driver-core-4.1.1.jar:na]
    at com.mongodb.client.internal.MongoClientDelegate$DelegateOperationExecutor.execute(MongoClientDelegate.java:178) ~[mongodb-driver-sync-4.1.1.jar:na]
    at com.mongodb.client.internal.MongoIterableImpl.execute(MongoIterableImpl.java:135) ~[mongodb-driver-sync-4.1.1.jar:na]
    at com.mongodb.client.internal.MongoIterableImpl.iterator(MongoIterableImpl.java:92) ~[mongodb-driver-sync-4.1.1.jar:na]
    at org.springframework.data.mongodb.core.MongoTemplate.executeFindMultiInternal(MongoTemplate.java:2790) ~[spring-data-mongodb-3.1.2.jar:3.1.2]
    ... 33 common frames omitted
Caused by: com.mongodb.MongoCommandException: Command failed with error 17 (ProtocolError): 'Attempt to switch database target during SASL authentication.' on server localhost:27017. The full response is {"ok": 0.0, "errmsg": "Attempt to switch database target during SASL authentication.", "code": 17, "codeName": "ProtocolError"}
    at com.mongodb.internal.connection.ProtocolHelper.getCommandFailureException(ProtocolHelper.java:175) ~[mongodb-driver-core-4.1.1.jar:na]
    at com.mongodb.internal.connection.InternalStreamConnection.receiveCommandMessageResponse(InternalStreamConnection.java:359) ~[mongodb-driver-core-4.1.1.jar:na]
    at com.mongodb.internal.connection.InternalStreamConnection.sendAndReceive(InternalStreamConnection.java:280) ~[mongodb-driver-core-4.1.1.jar:na]
    at com.mongodb.internal.connection.CommandHelper.sendAndReceive(CommandHelper.java:83) ~[mongodb-driver-core-4.1.1.jar:na]
    at com.mongodb.internal.connection.CommandHelper.executeCommand(CommandHelper.java:33) ~[mongodb-driver-core-4.1.1.jar:na]
    at com.mongodb.internal.connection.SaslAuthenticator.sendSaslContinue(SaslAuthenticator.java:195) ~[mongodb-driver-core-4.1.1.jar:na]
    at com.mongodb.internal.connection.SaslAuthenticator.access$200(SaslAuthenticator.java:43) ~[mongodb-driver-core-4.1.1.jar:na]
    at com.mongodb.internal.connection.SaslAuthenticator$1.run(SaslAuthenticator.java:69) ~[mongodb-driver-core-4.1.1.jar:na]
    ... 55 common frames omitted

我可以使用相同的凭据通过 Intellij Idea 客户端连接到 mongo。

我用 docker-compose 运行 mongo db

version: '3.1'

services:
  mongodb:
    image: mongo
    container_name: my-service-mongo
    restart: always
    environment:
      MONGO_INITDB_ROOT_USERNAME: user
      MONGO_INITDB_ROOT_PASSWORD: pass
      MONGO_INITDB_DATABASE: mydbname
    ports:
      - 27017:27017
    volumes:
      - ./mongo-init.js:/docker-entrypoint-initdb.d/mongo-init.js:ro

mongo-init.js 在哪里

db.createUser(
    {
        user: "user",
        pwd: "pass",
        roles: [
            {
                role: "readWrite",
                db: "mydbname"
            }
        ]
    }
);

发生了什么事?我在互联网上发现此错误消息的唯一地方是... mongo source code 8]。

任何帮助表示赞赏。

【问题讨论】:

  • 更新到最新的驱动程序,使用驱动程序教程仅通过驱动程序重现错误,如果仍然发生,请使用已发布的错误报告渠道向驱动程序报告。

标签: java mongodb spring-boot kotlin


【解决方案1】:

连同上面的@Lutoslaw 回答:回滚到 4.2.2 也适用于我。

我遇到了同样的错误 - 在 SASL 身份验证期间尝试切换数据库目标 - 在 createIndex 操作中。
这似乎是我在成功创建管理员后在普通用户下的第一次操作。

很高兴知道这些版本之间的身份验证机制发生了如此巨大的变化。

【讨论】:

    【解决方案2】:

    此答案可能与此问题没有直接关系,但希望对其他人有所帮助。如果您使用uri,那么@ChanningQiu 的答案很好。但是,如果您为每个参数使用属性,那么您可以尝试以下方式-

    spring:
      data:
        mongodb:
          host: localhost
          port: 27017
          database: db_name
          username: db_user_name
          password: db_password
          authentication-database: admin
    

    所以在这种情况下你需要设置authentication-database: admin 值。

    【讨论】:

      【解决方案3】:

      如果你:

      • 拥有多个相似的帐户(具有相同的凭据),一个在“admin”中,另一个在另一个数据库中。
      • 打算使用不在“admin”数据库中的其他帐户登录。
      • 启用 SASL。

      那么你可能会受到JAVA-4290的影响,这是由于在4.3.2之前的mongodb-driver-core版本中仅支持“admin”数据库的推测认证引起的。这导致客户端通过推测性身份验证成功地使用错误的帐户(管理数据库中的帐户)进行身份验证,只有在发送 SASL Continue 消息时 MongoDB 才会捕获错误。正如您所观察到的,它会出现协议错误。

      从 Spring Boot 2.5.4 开始,Spring Boot 附带的 mongodb-driver-core 版本只有 4.2.3。

      【讨论】:

        【解决方案4】:

        我遇到了同样的问题。我使用的是 spring-boot-starter-parent 2.4.1,它在最新的 mongodb docker 实例上运行良好。但是我必须连接到使用较低 mongo 的 Bitnami mongo docker 容器,然后发生了同样的错误。我将版本降级为2.3.7.RELEASE,然后获得了预期的行为而没有错误。

        对我来说,这个错误的原因是兼容性问题。参考 Spring data MongoDB Compatibility Matrix 查看不同版本和兼容性。

        编辑

        我在不同的应用程序中遇到了类似的错误。在这篇 stackoverflow 帖子 Mongodb could not find user "user@database" 的帮助下,我能够理解并解决问题。基本上,您需要正确指定身份验证数据库。如果没有,默认情况下,将在提供的数据库中检查用户,而不是在身份验证数据库中检查用户。在我的情况下,我指定了数据库 A,我的用户在 admin db 中。所以用户 admin 在数据库 A 中被检查。

        【讨论】:

          【解决方案5】:

          在 application.properties 中添加 spring.data.mongodb.authentication-database=admin 会将身份验证数据库设置为 admin。这相当于在您的连接字符串中添加?authSource=admin

          【讨论】:

          • 请在您发布的答案中添加更多详细信息,说明为什么此提议的更改解决了发布的问题。
          【解决方案6】:
          spring:
            data:
              mongodb:
                uri: mongodb://admin:admin@127.0.0.1:27017/dbname?authSource=admin
          

          添加 authSource 参数

          【讨论】:

          • 您好!太感谢了。这种方法对我有用)
          【解决方案7】:

          好像是mongo DB版本的bug

          4.4.3-bionic
          

          我已将 docker-compose 中的图像更改为

          mongo:3
          

          并且错误消失了。呃,这么多小时......

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2014-10-31
            • 1970-01-01
            • 2017-09-14
            • 2018-06-23
            • 2015-05-17
            • 2016-08-20
            • 1970-01-01
            • 2012-10-14
            相关资源
            最近更新 更多