【问题标题】:Spring securityconfig breaks deployment on google cloud app engineSpring securityconfig 中断了谷歌云应用引擎上的部署
【发布时间】:2021-07-30 19:00:12
【问题描述】:

我正在尝试将 springboot rest api 部署到谷歌云的应用引擎,但是我收到了这个错误:

org.springframework.context.ApplicationContextException: Unable to start ServletWebServerApplicationContext due to missing ServletWebServerFactory bean.

这是由这个类引起的,确切地说是扩展了 websecurityConfigurerAdapter:

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class ApplicationSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    APIUserDetailsService apiUserDetailsService;

    @Bean
    public DaoAuthenticationProvider authProvider() {
        DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider();
        authProvider.setUserDetailsService(apiUserDetailsService);
        authProvider.setPasswordEncoder(passwordEncoder());
        return authProvider;
    }

    private static final String[] AUTH_WHITELIST = {"/hello"};

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .cors().and()
                .csrf().disable()
                .sessionManagement().sessionCreationPolicy(STATELESS).and()
                .authorizeRequests()
                .antMatchers(AUTH_WHITELIST).permitAll()
                .anyRequest().authenticated()
                .and()
                .httpBasic();

        http.headers().frameOptions().disable();
    }

    @Bean
    PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

}

删除这个类完全修复错误,应用程序部署在应用程序引擎上并完美运行,尽管以不安全为代价。从我目前的理解来看,我们似乎必须使用谷歌应用引擎的网络服务器,而不是嵌入在 spring 中的默认 tomcat。因此,当应用程序部署时,它会尝试扩展不存在的 WebSecurityConfigurerAdapter,因为没有嵌入的 tomcat Web 服务器。我一直在尝试找到一种让它使用谷歌网络服务器的方法,有没有人知道在谷歌应用引擎上让它工作的方法?

POM xml:

<parent>
    <properties>
        <java.version>11</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-gcp-starter-sql-mysql</artifactId>
            <version>1.2.8.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>

    </dependencies>
</project>

主要:

@SpringBootApplication
@EnableCaching
public class OwlServerApplication {

    public static void main(String[] args) {
        SpringApplication.run(OwlServerApplication.class, args);

    }

错误的完整堆栈跟踪:

org.springframework.context.ApplicationContextException: Unable to start web server; nested exception is org.springframework.context.ApplicationContextException: Unable to start ServletWebServerApplicationContext due to missing ServletWebServerFactory bean.
at
org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.onRefresh (ServletWebServerApplicationContext.java:162)
at
org.springframework.context.support.AbstractApplicationContext.refresh (AbstractApplicationContext.java:582)
at
org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh (ServletWebServerApplicationContext.java:144)
at
org.springframework.boot.SpringApplication.refresh (SpringApplication.java:767)
at
org.springframework.boot.SpringApplication.refresh (SpringApplication.java:759)
at
org.springframework.boot.SpringApplication.refreshContext (SpringApplication.java:426)
at
org.springframework.boot.SpringApplication.run (SpringApplication.java:326)
at
org.springframework.boot.SpringApplication.run (SpringApplication.java:1309)
at
org.springframework.boot.SpringApplication.run (SpringApplication.java:1298)
at
com.owl.owlserver.OwlServerApplication.main (OwlServerApplication.java:12)
Caused by: org.springframework.context.ApplicationContextException: Unable to start ServletWebServerApplicationContext due to missing ServletWebServerFactory bean.
at
org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.getWebServerFactory (ServletWebServerApplicationContext.java:209)
at
org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.createWebServer (ServletWebServerApplicationContext.java:179)
at
org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.onRefresh (ServletWebServerApplicationContext.java:159)

通过添加。 3.1 servlet 我们现在得到这个错误:

org.springframework.beans.factory.BeanDefinitionStoreException: Failed to parse configuration class [com.example.demo.DemoApplication]; nested exception is java.io.FileNotFoundException: class path resource [org/springframework/security/config/annotation/web/configuration/WebSecurityConfigurerAdapter.class] cannot be opened because it does not exist
    at org.springframework.context.annotation.ConfigurationClassParser.parse(ConfigurationClassParser.java:189)
    at org.springframework.context.annotation.ConfigurationClassPostProcessor.processConfigBeanDefinitions(ConfigurationClassPostProcessor.java:331)
    at org.springframework.context.annotation.ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry(ConfigurationClassPostProcessor.java:247)
    at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanDefinitionRegistryPostProcessors(PostProcessorRegistrationDelegate.java:311)
    at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:112)
    at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:746)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:564)
    at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:144)
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:782)
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:774)
    at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:439)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:339)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1340)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1329)
    at com.example.demo.DemoApplication.main(DemoApplication.java:18)
Caused by: java.io.FileNotFoundException: class path resource [org/springframework/security/config/annotation/web/configuration/WebSecurityConfigurerAdapter.class] cannot be opened because it does not exist
    at org.springframework.core.io.ClassPathResource.getInputStream(ClassPathResource.java:187)
    at org.springframework.core.type.classreading.SimpleMetadataReader.getClassReader(SimpleMetadataReader.java:55)
    at org.springframework.core.type.classreading.SimpleMetadataReader.<init>(SimpleMetadataReader.java:49)
    at org.springframework.core.type.classreading.SimpleMetadataReaderFactory.getMetadataReader(SimpleMetadataReaderFactory.java:103)
    at org.springframework.boot.type.classreading.ConcurrentReferenceCachingMetadataReaderFactory.createMetadataReader(ConcurrentReferenceCachingMetadataReaderFactory.java:86)
    at org.springframework.boot.type.classreading.ConcurrentReferenceCachingMetadataReaderFactory.getMetadataReader(ConcurrentReferenceCachingMetadataReaderFactory.java:73)
    at org.springframework.core.type.classreading.SimpleMetadataReaderFactory.getMetadataReader(SimpleMetadataReaderFactory.java:81)
    at org.springframework.context.annotation.ConfigurationClassParser.asSourceClass(ConfigurationClassParser.java:696)
    at org.springframework.context.annotation.ConfigurationClassParser$SourceClass.getSuperClass(ConfigurationClassParser.java:1010)
    at org.springframework.context.annotation.ConfigurationClassParser.doProcessConfigurationClass(ConfigurationClassParser.java:341)
    at org.springframework.context.annotation.ConfigurationClassParser.processConfigurationClass(ConfigurationClassParser.java:250)
    at org.springframework.context.annotation.ConfigurationClassParser.parse(ConfigurationClassParser.java:199)
    at org.springframework.context.annotation.ConfigurationClassParser.doProcessConfigurationClass(ConfigurationClassParser.java:304)
    at org.springframework.context.annotation.ConfigurationClassParser.processConfigurationClass(ConfigurationClassParser.java:250)
    at org.springframework.context.annotation.ConfigurationClassParser.parse(ConfigurationClassParser.java:207)
    at org.springframework.context.annotation.ConfigurationClassParser.parse(ConfigurationClassParser.java:175)
    ... 14 common frames omitted 

应用引擎似乎找不到 websecurityconfigurerAdapter 类。

【问题讨论】:

  • 确保 app.yaml 文件创建正确。 java11 的应用引擎需要提供运行时。
  • 是的,我有正确的 yaml,因为当我删除类时应用程序部署和运行完美。
  • 您能否提及应用程序在开发机器上使用 SecurityConfig 是否可以顺利运行?
  • 另外,发布整个堆栈跟踪也会有所帮助。我想还有其他原因导致“丢失的 bean”。
  • @justthink 是的,它在本地安全配置下运行得很好,它在 heroku 上也运行得很好。所以这绝对是谷歌应用引擎的事情。我编辑问题以发布堆栈跟踪,非常感谢您的帮助。

标签: java spring google-app-engine google-cloud-platform spring-security


【解决方案1】:

虽然我不确定是什么导致了这个问题,但这里的一个常见解决方案是通过以下方式配置自动配置。

@EnableAutoConfiguration
@SpringBootApplication
@EnableCaching
public class OwlServerApplication {

    public static void main(String[] args) {
        SpringApplication.run(OwlServerApplication.class, args);

    }

此注解@EnableAutoConfiguration 确保配置bean 可以从同级或子包路径扫描,也可以自动配置。

同时,确保您在同一个包或同级包中有 ApplicationSecurityConfig 类。


Springboot 和 Google App Engine 都没有明确提到这个 Servlet 版本问题。

我在这里找到了这个答案https://stackoverflow.com/a/28869503/15262845

如果我猜对了(我之前从未使用过 Google App Engine),Google App Engine 支持 Sevlet 2.5,但它需要上面的 Servlet 3.1 才能正确初始化扩展 WebSecurityConfigurerAdapter 的 bean。

<dependency>
  <groupId>javax.servlet</groupId>
  <artifactId>javax.servlet-api</artifactId>
  <version>3.1.0</version>
  <type>jar</type>
  <scope>provided</scope>
</dependency>

另请参阅 Google Cloud Engine 的官方指南以迁移到 Servlet 3.1 https://javaee.github.io/servlet-spec/ 另见答案Upgrade App Engine servlet-api-2.5 to servlet-api-3.1?


让我知道它是否有效或还有更多需要讨论。

【讨论】:

  • 添加“@EnableAutoConfiguration”会给出“冗余声明:“@SpringBootApplication”已经应用“@EnableAutoConfiguration”的警告,这是有道理的,因为“@SpringbootApplication”会在启动时扫描组件和bean .所以好像不是这样的。我在同一个包中也有 Appsecurityconfig 和上面的主类。
  • 那做了什么!,我们到了这里,错误改变了,它现在抛出了一个新的错误,我在上面添加了。我将尝试进一步调试这个新错误,但非常感谢你,任何进一步的见解将不胜感激。
  • 非常好的问题!现在我知道 servlet 环境可以停止初始化 Web 服务器 bean。
猜你喜欢
  • 2021-07-30
  • 1970-01-01
  • 2021-02-04
  • 2020-07-14
  • 2022-07-27
  • 2018-10-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多