使用 Spanner 模拟器在 java spring 引导项目中创建 Spanner 会话时权限被拒绝

Permission denied in getting spanner session create in a java spring boot project using spanner emulator

我正在尝试 运行 一个基本的 spring 使用 JPA 的引导应用程序,方法是使用 Spanner 模拟器。但是,在达到任何暴露的端点后启动后出现以下错误。

PERMISSION_DENIED: com.google.api.gax.rpc.PermissionDeniedException: io.grpc.StatusRuntimeException: PERMISSION_DENIED: Caller is missing IAM permission spanner.sessions.create on resource projects/test-project/instances/test-instance/databases/test-database.

项目已从 https://github.com/GoogleCloudPlatform/google-cloud-spanner-hibernate/tree/master/google-cloud-spanner-hibernate-samples/spring-data-jpa-sample 克隆 我所做的唯一更改是更新 application.properties 文件。 根据我的理解,spanner 模拟器不应该有任何与 IAM 相关的问题,因为它不需要任何问题。我不确定是什么导致了这个问题。我已验证模拟器配置是活动配置,因此我希望代码连接到模拟器。

# Application configuration to use Cloud Spanner with Spring Data JPA

# Spanner connection URL.
# - ${PROJECT_ID} Replace with your GCP project ID
# - ${INSTANCE_ID} Replace with your Spanner instance ID
# - ${DATABASE_NAME} Replace with your Spanner database name within your Spanner instance
spring.datasource.url=jdbc:cloudspanner:/projects/test-project/instances/test-instance/databases/test-database

# Specify the Spanner JDBC driver.
spring.datasource.driver-class-name=com.google.cloud.spanner.jdbc.JdbcDriver

# Specify the Spanner Hibernate dialect.
spring.jpa.properties.hibernate.dialect=com.google.cloud.spanner.hibernate.SpannerDialect

#spring.jpa.hibernate.ddl-auto=update //same error even if I uncomment this line

# Settings to enable batching statements for efficiency
spring.jpa.properties.hibernate.jdbc.batch_size=100

# You may display SQL statements and stats for debugging if needed.
spring.jpa.properties.hibernate.show_sql=true
spring.jpa.properties.hibernate.format_sql=true

请在下面找到控制台日志:

2021-10-06 12:59:12.549  INFO 9747 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8080 (http)
2021-10-06 12:59:12.556  INFO 9747 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2021-10-06 12:59:12.556  INFO 9747 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet engine: [Apache Tomcat/9.0.53]
2021-10-06 12:59:12.617  INFO 9747 --- [           main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2021-10-06 12:59:12.617  INFO 9747 --- [           main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 694 ms
2021-10-06 12:59:12.707  INFO 9747 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Starting...
2021-10-06 12:59:12.737  WARN 9747 --- [           main] c.g.a.oauth2.DefaultCredentialsProvider  : Your application has authenticated using end user credentials from Google Cloud SDK. We recommend that most server applications use service accounts instead. If your application continues to use end user credentials from Cloud SDK, you might receive a "quota exceeded" or "API not enabled" error. For more information about service accounts, see https://cloud.google.com/docs/authentication/.
2021-10-06 12:59:14.558  INFO 9747 --- [           main] com.zaxxer.hikari.pool.PoolBase          : HikariPool-1 - Driver does not support get/set network timeout for connections. (Network timeout is not supported)
2021-10-06 12:59:22.165  INFO 9747 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Start completed.
2021-10-06 12:59:22.197  INFO 9747 --- [           main] o.hibernate.jpa.internal.util.LogHelper  : HHH000204: Processing PersistenceUnitInfo [name: default]
2021-10-06 12:59:22.231  INFO 9747 --- [           main] org.hibernate.Version                    : HHH000412: Hibernate ORM core version 5.4.29.Final
2021-10-06 12:59:22.337  INFO 9747 --- [           main] o.hibernate.annotations.common.Version   : HCANN000001: Hibernate Commons Annotations {5.1.2.Final}
2021-10-06 12:59:22.396  INFO 9747 --- [           main] org.hibernate.dialect.Dialect            : HHH000400: Using dialect: com.google.cloud.spanner.hibernate.SpannerDialect
2021-10-06 12:59:22.851  INFO 9747 --- [           main] o.h.e.t.j.p.i.JtaPlatformInitiator       : HHH000490: Using JtaPlatform implementation: [org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform]
2021-10-06 12:59:22.857  INFO 9747 --- [           main] j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'default'
2021-10-06 12:59:23.060  WARN 9747 --- [           main] JpaBaseConfiguration$JpaWebConfiguration : spring.jpa.open-in-view is enabled by default. Therefore, database queries may be performed during view rendering. Explicitly configure spring.jpa.open-in-view to disable this warning
2021-10-06 12:59:23.184  INFO 9747 --- [           main] o.s.b.a.w.s.WelcomePageHandlerMapping    : Adding welcome page template: index
2021-10-06 12:59:23.290  INFO 9747 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
2021-10-06 12:59:23.298  INFO 9747 --- [           main] com.example.CoffeeApplication            : Started CoffeeApplication in 12.957 seconds (JVM running for 13.227)
2021-10-06 12:59:33.646  INFO 9747 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring DispatcherServlet 'dispatcherServlet'
2021-10-06 12:59:33.646  INFO 9747 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Initializing Servlet 'dispatcherServlet'
2021-10-06 12:59:33.647  INFO 9747 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Completed initialization in 1 ms
Hibernate: 
    select
        customer0_.id as id1_1_,
        customer0_.email as email2_1_,
        customer0_.name as name3_1_ 
    from
        customer customer0_
2021-10-06 12:59:35.650  WARN 9747 --- [nio-8080-exec-1] o.h.engine.jdbc.spi.SqlExceptionHelper   : SQL Error: 7, SQLState: null
2021-10-06 12:59:35.650 ERROR 9747 --- [nio-8080-exec-1] o.h.engine.jdbc.spi.SqlExceptionHelper   : PERMISSION_DENIED: com.google.api.gax.rpc.PermissionDeniedException: io.grpc.StatusRuntimeException: PERMISSION_DENIED: Caller is missing IAM permission spanner.sessions.create on resource projects/test-project/instances/test-instance/databases/test-database.
2021-10-06 12:59:35.668 ERROR 9747 --- [nio-8080-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.orm.jpa.JpaSystemException: could not extract ResultSet; nested exception is org.hibernate.exception.GenericJDBCException: could not extract ResultSet] with root cause

io.grpc.StatusRuntimeException: PERMISSION_DENIED: Caller is missing IAM permission spanner.sessions.create on resource projects/test-project/instances/test-instance/databases/test-database.
        at io.grpc.Status.asRuntimeException(Status.java:535) ~[grpc-api-1.40.1.jar:1.40.1]
        at io.grpc.stub.ClientCalls$UnaryStreamToFuture.onClose(ClientCalls.java:533) ~[grpc-stub-1.40.1.jar:1.40.1]
        at io.grpc.PartialForwardingClientCallListener.onClose(PartialForwardingClientCallListener.java:39) ~[grpc-api-1.40.1.jar:1.40.1]
        at io.grpc.ForwardingClientCallListener.onClose(ForwardingClientCallListener.java:23) ~[grpc-api-1.40.1.jar:1.40.1]
        at io.grpc.ForwardingClientCallListener$SimpleForwardingClientCallListener.onClose(ForwardingClientCallListener.java:40) ~[grpc-api-1.40.1.jar:1.40.1]
        at com.google.cloud.spanner.spi.v1.SpannerErrorInterceptor.onClose(SpannerErrorInterceptor.java:100) ~[google-cloud-spanner-6.12.5.jar:6.12.5]
        at io.grpc.internal.ClientCallImpl.closeObserver(ClientCallImpl.java:557) ~[grpc-core-1.40.1.jar:1.40.1]
        at io.grpc.internal.ClientCallImpl.access0(ClientCallImpl.java:69) ~[grpc-core-1.40.1.jar:1.40.1]
        at io.grpc.internal.ClientCallImpl$ClientStreamListenerImplStreamClosed.runInternal(ClientCallImpl.java:738) ~[grpc-core-1.40.1.jar:1.40.1]
        at io.grpc.internal.ClientCallImpl$ClientStreamListenerImplStreamClosed.runInContext(ClientCallImpl.java:717) ~[grpc-core-1.40.1.jar:1.40.1]
        at io.grpc.internal.ContextRunnable.run(ContextRunnable.java:37) ~[grpc-core-1.40.1.jar:1.40.1]
        at io.grpc.internal.SerializingExecutor.run(SerializingExecutor.java:133) ~[grpc-core-1.40.1.jar:1.40.1]
        at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) ~[na:1.8.0_281]
        at java.util.concurrent.FutureTask.run(FutureTask.java:266) ~[na:1.8.0_281]
        at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access1(ScheduledThreadPoolExecutor.java:180) ~[na:1.8.0_281]
        at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293) ~[na:1.8.0_281]
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) ~[na:1.8.0_281]
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) ~[na:1.8.0_281]
        at java.lang.Thread.run(Thread.java:748) [na:1.8.0_281]


该错误清楚地表明您的应用程序并未尝试连接到模拟器,而是连接到真实的 Spanner 数据库。为了连接到模拟器而不是 'real' Cloud Spanner,您应该执行以下 一个 操作:

  1. 设置环境变量SPANNER_EMULATOR_HOST=localhost:9010
  2. 或者:编辑 JDBC 连接 URL 以包含 autoConfigEmulator=true 属性。您的 JDBC URL 将变为 jdbc:cloudspanner:/projects/test-project/instances/test-instance/databases/test-database;autoConfigEmulator=true

第二种选择的优点是 autoConfigEmulator 属性 不仅会确保 JDBC 驱动程序连接到模拟器,它还会自动创建 test-instancetest-database 在模拟器上(如果它们尚不存在)。