Spring Boot Security 导致应用程序在本地一切正常时部署到 GAE 时关闭

Spring Boot Security causes application to shutdown when deployed to GAE when locally everything works fine

我在 Google App Engine 上遇到 Spring 安全和 OAuth 2.0 问题。

我使用 this tutorial 设置了 OAuth,在本地一切正常。当访问“/”以外的任何端点时,您将被重定向到 Google 登录页面。

当我将应用程序部署到 Google App Engine 时出现问题。

应用程序不断重启并且日志不是很清楚。我尝试从头开始设置所有内容,我发现即使仅更改 pom.xml 文件并添加 spring-boot-starter-security spring-boot-starter-oauth2-client 依赖而不添加任何与安全相关的代码会导致应用程序重新启动。

我认为这可能与安全自动配置有关,但我主要是 .NET 开发人员,我真的不知道如何找到这个错误。

我希望应用程序在 GAE 上像在本地一样正常工作。

我的pom.xml文件如下所示:

    <?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <artifactId>time-off-backend</artifactId>
    <packaging>jar</packaging>
    <name>time-off-backend</name>
    <description>Time-off project</description>

    <groupId>pl.devapo</groupId>
    <version>1.0.0</version>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>11</java.version>
    </properties>
    <profiles>
        <profile>
            <id>cloud-gcp</id>
            <dependencies>
                <dependency>
                    <groupId>org.springframework.cloud</groupId>
                    <artifactId>spring-cloud-gcp-starter</artifactId>
                    <version>1.1.1.RELEASE</version>
                </dependency>
                <dependency>
                    <groupId>org.springframework.cloud</groupId>
                    <artifactId>spring-cloud-gcp-starter-sql-mysql</artifactId>
                    <version>1.0.0.RELEASE</version>
                </dependency>
            </dependencies>
            <build>
                <plugins>
                    <plugin>
                        <groupId>com.google.cloud.tools</groupId>
                        <artifactId>appengine-maven-plugin</artifactId>
                        <version>1.3.2</version>
                    </plugin>
                </plugins>
            </build>
        </profile>
    </profiles>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
            <version>2.4.4</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            
            <version>2.4.4</version>
        </dependency>
        <dependency>
            <groupId>commons-beanutils</groupId>
            <artifactId>commons-beanutils</artifactId>
            <version>1.9.4</version>
        </dependency>
        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
            <version>1.4.200</version>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
            <version>1.18.20</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <version>2.4.4</version>
        </dependency>
        <dependency>
            <groupId>javax.xml.bind</groupId>
            <artifactId>jaxb-api</artifactId>
            <version>2.3.0</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-validation</artifactId>
            <version>2.4.4</version>
        </dependency>
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
            <version>2.9.2</version>
            <exclusions>
                <exclusion>
                    <groupId>com.fasterxml.jackson.core</groupId>
                    <artifactId>jackson-annotations</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger-ui</artifactId>
            <version>2.9.2</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-oauth2-client</artifactId>
            <version>2.5.2</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
            <version>2.5.2</version>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <mainClass>
                        pl.devapo.timeoff.TimeOffApplication
                    </mainClass>
                </configuration>
                <executions>
                    <execution>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
            <!--            todo delete-->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>11</source>
                    <target>11</target>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

app-test.yaml 文件:

runtime: java11
service: backend-test
entrypoint: java -Xmx64m -jar target/time-off-backend-1.0.0.jar --debug
env_variables:
  SPRING_PROFILES_ACTIVE: "test"
  DATABASE_USERNAME: ...
  DATABASE_PASSWORD: ...
handlers:
  - url: /.*
    script: this field is required, but ignored
manual_scaling:
  instances: 1

在我的 application.properties 文件中,我添加了这两行:

spring.security.oauth2.client.registration.google.client-id=...
spring.security.oauth2.client.registration.google.client-secret=...

最后是我的 SecurityConfig.java 文件:

package pl.devapo.timeoff.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    public void configure(HttpSecurity http) throws Exception {

        http
                .antMatcher("/**").authorizeRequests()
                .antMatchers(new String[]{"/", "/not-restricted"}).permitAll()
                .anyRequest().authenticated()
                .and()
                .oauth2Login();
    }
}

日志如下所示:

2021-07-20 17:07:56 backend-test[20210720t190541]    .   ____          _            __ _ _
2021-07-20 17:07:56 backend-test[20210720t190541]   /\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
2021-07-20 17:07:56 backend-test[20210720t190541]  ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
2021-07-20 17:07:56 backend-test[20210720t190541]   \/  ___)| |_)| | | | | || (_| |  ) ) ) )
2021-07-20 17:07:56 backend-test[20210720t190541]    '  |____| .__|_| |_|_| |_\__, | / / / /
2021-07-20 17:07:56 backend-test[20210720t190541]   =========|_|==============|___/=/_/_/_/
2021-07-20 17:07:56 backend-test[20210720t190541]   :: Spring Boot ::                (v2.4.4)
2021-07-20 17:07:56 backend-test[20210720t190541]
2021-07-20 17:07:57 backend-test[20210720t190541]  2021-07-20 17:07:57.024  INFO 10 --- [           main] pl.devapo.timeoff.TimeOffApplication     : Starting TimeOffApplication using Java 11.0.11 on localhost with PID 10 (/workspace/target/time-off-backend-1.0.0.jar started by www-data in /workspace)
2021-07-20 17:07:57 backend-test[20210720t190541]  2021-07-20 17:07:57.028  INFO 10 --- [           main] pl.devapo.timeoff.TimeOffApplication     : The following profiles are active: test
2021-07-20 17:07:58 backend-test[20210720t190541]  2021-07-20 17:07:58.759  INFO 10 --- [           main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data JPA repositories in DEFAULT mode.
2021-07-20 17:07:58 backend-test[20210720t190541]  2021-07-20 17:07:58.919  INFO 10 --- [           main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 148 ms. Found 6 JPA repository interfaces.
2021-07-20 17:08:00 backend-test[20210720t190541]  2021-07-20 17:08:00.006  INFO 10 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8080 (http)
2021-07-20 17:08:00 backend-test[20210720t190541]  2021-07-20 17:08:00.024  INFO 10 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2021-07-20 17:08:00 backend-test[20210720t190541]  2021-07-20 17:08:00.024  INFO 10 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet engine: [Apache Tomcat/9.0.44]
2021-07-20 17:08:00 backend-test[20210720t190541]  2021-07-20 17:08:00.108  INFO 10 --- [           main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2021-07-20 17:08:00 backend-test[20210720t190541]  2021-07-20 17:08:00.108  INFO 10 --- [           main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 2967 ms
2021-07-20 17:08:00 backend-test[20210720t190541]  2021-07-20 17:08:00.836  INFO 10 --- [           main] o.hibernate.jpa.internal.util.LogHelper  : HHH000204: Processing PersistenceUnitInfo [name: default]
2021-07-20 17:08:00 backend-test[20210720t190541]  2021-07-20 17:08:00.929  INFO 10 --- [           main] org.hibernate.Version                    : HHH000412: Hibernate ORM core version 5.4.29.Final
2021-07-20 17:08:01 backend-test[20210720t190541]  2021-07-20 17:08:01.162  INFO 10 --- [           main] o.hibernate.annotations.common.Version   : HCANN000001: Hibernate Commons Annotations {5.1.2.Final}
2021-07-20 17:08:01 backend-test[20210720t190541]  2021-07-20 17:08:01.320  INFO 10 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Starting...
2021-07-20 17:08:01 backend-test[20210720t190541]  2021-07-20 17:08:01.649  INFO 10 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Start completed.
2021-07-20 17:08:01 backend-test[20210720t190541]  2021-07-20 17:08:01.705  INFO 10 --- [           main] org.hibernate.dialect.Dialect            : HHH000400: Using dialect: org.hibernate.dialect.H2Dialect
2021-07-20 17:08:03 backend-test[20210720t190541]  2021-07-20 17:08:03.478  INFO 10 --- [           main] o.h.e.t.j.p.i.JtaPlatformInitiator       : HHH000490: Using JtaPlatform implementation: [org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform]
2021-07-20 17:08:03 backend-test[20210720t190541]  2021-07-20 17:08:03.501  INFO 10 --- [           main] j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'default'
2021-07-20 17:08:04 backend-test[20210720t190541]  2021-07-20 17:08:04.444  WARN 10 --- [           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-07-20 17:08:05 backend-test[20210720t190541]  2021-07-20 17:08:05.096  INFO 10 --- [           main] pertySourcedRequestMappingHandlerMapping : Mapped URL path [/v2/api-docs] onto method [springfox.documentation.swagger2.web.Swagger2Controller#getDocumentation(String, HttpServletRequest)]
2021-07-20 17:08:05 backend-test[20210720t190541]  2021-07-20 17:08:05.407  INFO 10 --- [           main] o.s.s.concurrent.ThreadPoolTaskExecutor  : Initializing ExecutorService 'applicationTaskExecutor'
2021-07-20 17:08:06 backend-test[20210720t190541]  2021-07-20 17:08:06.071  INFO 10 --- [           main] o.s.s.web.DefaultSecurityFilterChain     : Will secure Ant [pattern='/**'] with [org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@2ac519dc, org.springframework.security.web.context.SecurityContextPersistenceFilter@2b73bd6b, org.springframework.security.web.header.HeaderWriterFilter@5f0bab7e, org.springframework.security.web.csrf.CsrfFilter@1eb9a3ef, org.springframework.security.web.authentication.logout.LogoutFilter@2da81754, org.springframework.security.oauth2.client.web.OAuth2AuthorizationRequestRedirectFilter@5e593b08, org.springframework.security.oauth2.client.web.OAuth2LoginAuthenticationFilter@3946075, org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter@4998e74b, org.springframework.security.web.authentication.ui.DefaultLogoutPageGeneratingFilter@3d53e6f7, org.springframework.security.web.savedrequest.RequestCacheAwareFilter@750ed637, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@18d11527, org.springframework.security.web.authentication.AnonymousAuthenticationFilter@1de4bee0, org.springframework.security.web.session.SessionManagementFilter@337a6d30, org.springframework.security.web.access.ExceptionTranslationFilter@58fd1214, org.springframework.security.web.access.intercept.FilterSecurityInterceptor@3fe512d2]
2021-07-20 17:08:06 backend-test[20210720t190541]  2021-07-20 17:08:06.163  INFO 10 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
2021-07-20 17:08:06 backend-test[20210720t190541]  2021-07-20 17:08:06.166  INFO 10 --- [           main] d.s.w.p.DocumentationPluginsBootstrapper : Context refreshed
2021-07-20 17:08:06 backend-test[20210720t190541]  2021-07-20 17:08:06.244  INFO 10 --- [           main] d.s.w.p.DocumentationPluginsBootstrapper : Found 1 custom documentation plugin(s)
2021-07-20 17:08:06 backend-test[20210720t190541]  2021-07-20 17:08:06.311  INFO 10 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring DispatcherServlet 'dispatcherServlet'
2021-07-20 17:08:06 backend-test[20210720t190541]  2021-07-20 17:08:06.312  INFO 10 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Initializing Servlet 'dispatcherServlet'
2021-07-20 17:08:06 backend-test[20210720t190541]  2021-07-20 17:08:06.343  INFO 10 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Completed initialization in 31 ms
2021-07-20 17:08:06 backend-test[20210720t190541]  2021-07-20 17:08:06.346  INFO 10 --- [           main] s.d.s.w.s.ApiListingReferenceScanner     : Scanning for api listing references
2021-07-20 17:08:06 backend-test[20210720t190541]  2021-07-20 17:08:06.617  INFO 10 --- [           main] .d.s.w.r.o.CachingOperationNameGenerator : Generating unique operation named: findUsingGET_1
2021-07-20 17:08:06 backend-test[20210720t190541]  2021-07-20 17:08:06.620  INFO 10 --- [           main] .d.s.w.r.o.CachingOperationNameGenerator : Generating unique operation named: getUsingGET_1
2021-07-20 17:08:06 backend-test[20210720t190541]  2021-07-20 17:08:06.655  INFO 10 --- [           main] .d.s.w.r.o.CachingOperationNameGenerator : Generating unique operation named: findUsingGET_2
2021-07-20 17:08:06 backend-test[20210720t190541]  2021-07-20 17:08:06.657  INFO 10 --- [           main] .d.s.w.r.o.CachingOperationNameGenerator : Generating unique operation named: getUsingGET_2
2021-07-20 17:08:06 backend-test[20210720t190541]  2021-07-20 17:08:06.669  INFO 10 --- [           main] .d.s.w.r.o.CachingOperationNameGenerator : Generating unique operation named: findUsingGET_3
2021-07-20 17:08:06 backend-test[20210720t190541]  2021-07-20 17:08:06.671  INFO 10 --- [           main] .d.s.w.r.o.CachingOperationNameGenerator : Generating unique operation named: getUsingGET_3
2021-07-20 17:08:06 backend-test[20210720t190541]  2021-07-20 17:08:06.687  INFO 10 --- [           main] .d.s.w.r.o.CachingOperationNameGenerator : Generating unique operation named: cancelUsingPOST_1
2021-07-20 17:08:06 backend-test[20210720t190541]  2021-07-20 17:08:06.695  INFO 10 --- [           main] .d.s.w.r.o.CachingOperationNameGenerator : Generating unique operation named: findUsingGET_4
2021-07-20 17:08:06 backend-test[20210720t190541]  2021-07-20 17:08:06.697  INFO 10 --- [           main] .d.s.w.r.o.CachingOperationNameGenerator : Generating unique operation named: getUsingGET_4
2021-07-20 17:08:06 backend-test[20210720t190541]  2021-07-20 17:08:06.705  INFO 10 --- [           main] .d.s.w.r.o.CachingOperationNameGenerator : Generating unique operation named: saveUsingPOST_1
2021-07-20 17:08:06 backend-test[20210720t190541]  2021-07-20 17:08:06.769  INFO 10 --- [           main] pl.devapo.timeoff.TimeOffApplication     : Started TimeOffApplication in 10.578 seconds (JVM running for 11.602)
2021-07-20 17:08:06 backend-test[20210720t190541]  2021-07-20 17:08:06.796  INFO 10 --- [extShutdownHook] o.s.s.concurrent.ThreadPoolTaskExecutor  : Shutting down ExecutorService 'applicationTaskExecutor'
2021-07-20 17:08:06 backend-test[20210720t190541]  2021-07-20 17:08:06.801  INFO 10 --- [extShutdownHook] j.LocalContainerEntityManagerFactoryBean : Closing JPA EntityManagerFactory for persistence unit 'default'
2021-07-20 17:08:06 backend-test[20210720t190541]  2021-07-20 17:08:06.804  INFO 10 --- [extShutdownHook] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Shutdown initiated...
2021-07-20 17:08:06 backend-test[20210720t190541]  2021-07-20 17:08:06.808  INFO 10 --- [extShutdownHook] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Shutdown completed.
2021-07-20 17:08:07 backend-test[20210720t190541]  {"severity": "WARNING", "message": "App is listening on port 8080. We recommend your app listen on the port defined by the PORT environment variable to take advantage of an NGINX layer on port 8080."}\n

在调试级别查看日志后,我们发现 GAE 需要端点 /_ah/start 来启动应用程序,因为 spring 安全自动配置默认保护所有端点您需要解除 /_ah/start 端点的安全才能使其在 GAE 上正常运行。

因此,将这些添加到我们的 SecurityConfig 配置方法后,一切都开始运行良好:

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    public void configure(HttpSecurity http) throws Exception {

        http.authorizeRequests()
                .antMatchers("/_ah/start").permitAll()
                .and()
                .antMatcher("/**").authorizeRequests()
                .anyRequest().authenticated()
                .and()
                .oauth2Login();
    }
}