【发布时间】:2020-07-17 09:47:23
【问题描述】:
我有一个简单的 Spring Boot 2.3.1 应用程序,它使用 Spring Security 来管理用户登录/注销(使用最新的依赖项)。用户/角色域模型存储的后端存储是 Postgres(我正在使用 JPA 来访问它们)。在本地一切正常,但是当我通过 gcloud app deploy 部署到 GAE 时,站点上的每个页面——甚至是 /login——页面都尝试加载 30 秒,然后出现以下 500 错误消息:
Error: Server Error
The server encountered an error and could not complete your request.
Please try again in 30 seconds.
使用gcloud app logs tail -s default 查看 GAE 错误日志会显示所有正常行为。与 Postgres 的数据库连接很好,没有 WARN 或 ERROR 块。我几乎想知道它是否比我的代码拦截请求然后停止更高级,比如 ELB?
这是我的pom.xml:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
<exclusions>
<exclusion>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>
<dependency>
<groupId>com.lmax</groupId>
<artifactId>disruptor</artifactId>
<version>3.4.2</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>nz.net.ultraq.thymeleaf</groupId>
<artifactId>thymeleaf-layout-dialect</artifactId>
<version>2.3.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>com.google.cloud.sql</groupId>
<artifactId>postgres-socket-factory</artifactId>
<version>1.0.16</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Hoxton.SR6</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
以及带有 Spring Security 覆盖的 @Configuration 类:
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private DataSource dataSource;
@Autowired
private MemberService memberService;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
String authByUsernameQuery = "select m.username as principal, name from member m" +
" inner join member_role mr on m.id = mr.member_id" +
" inner join role r on mr.role_id = r.id" +
" where m.username=?";
auth.jdbcAuthentication().dataSource(dataSource)
.usersByUsernameQuery("select username as principal, password as credentials, true from member where username=?")
.authoritiesByUsernameQuery(authByUsernameQuery)
.passwordEncoder(passwordEncoder()).rolePrefix("ROLE_");
}
@Bean
public BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
public AuthenticationManager customAuthenticationManager() throws Exception {
return authenticationManager();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable();
// force https -- does this need more work somehow?
// Still doesn't work in GAE when commented out
http.requiresChannel()
.anyRequest().requiresSecure();
http.authorizeRequests().antMatchers("/register", "/login", "/status").permitAll()
.antMatchers("/index").hasAnyRole("USER, ADMIN")
.and().formLogin().loginPage("/login").permitAll()
.defaultSuccessUrl("/")
// smart logout from spring (no need for explicit endpoint)
.and().logout().logoutRequestMatcher(new AntPathRequestMatcher("/logout")).logoutSuccessUrl("/login");
}
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(memberService).passwordEncoder(passwordEncoder());
}
}
下面是带有登录方法的控制器示例,但由于停顿,我无法访问此允许的页面:
@Controller
public class MemberController {
private static final Logger log = LoggerFactory.getLogger(MemberController.class);
@Autowired
private MemberService memberService;
@Autowired
private AppConfig appConfig;
@RequestMapping("/status")
@GetMapping
public String check() {
return "OK";
}
@GetMapping("/login")
public String showLoginForm(){
return "views/loginForm";
}
因此,那些端点——以及我尝试过的所有其他端点——都会挂起,直到出现错误。项目 UI 页面使用 Thymeleaf 和资源/中的标准设置:
我现在被阻止了。我进行了一个更简单的实验来部署另一个没有 Spring Security 的 Java 应用程序,它工作得很好。然后我将 Spring Security 添加到这个更简单的项目中,它会起作用,因为我会立即收到 Spring Security 的默认登录屏幕的提示。然而我的代码一切都挂了,我从来没有成功加载过一个页面。我觉得它一定是我还没有为 HTTPS/SSL/Cert 添加的东西,但我不知道是什么。
有什么想法吗?提前致谢。
【问题讨论】:
标签: java spring-boot google-cloud-platform spring-security