自定义登录表单。 配置Spring安全性以获取JSON响应

我有一个简单的应用程序,分为两部分:

  • 一个后端,它使用Spring-boot / Spring-security公开REST服务
  • 一个只包含静态文件的前端。

这些请求由侦听端口80的nginx服务器接收。

  • 如果请求URL以/ api /开头,请求将重定向到后端。
  • 否则,请求由提供静态文件的nginx处理。

我创建了一个自定义登录表单(在前端部分),我正在尝试配置Spring-boot服务器。

有很多例子我可以看到如何定义“登录成功”url和“登录错误”url,但我不希望Spring-security重定向用户。 如果登录成功或HTTP 40x登录失败,我希望Spring-security使用HTTP 200回答。

换句话说:我希望后端只回答JSON,而不是HTML。

到目前为止,当我提交登录表单时,请求被重定向,我得到默认的Spring登录表单作为答案。

我尝试使用.formLogin().loginProcessingUrl("/login"); 而不是loginPage("")

 @Configuration @Order(SecurityProperties.ACCESS_OVERRIDE_ORDER) protected static class SecurityConfiguration extends WebSecurityConfigurerAdapter { @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.inMemoryAuthentication() .withUser("user").password("password").roles("ADMIN"); } @Override public void configure(HttpSecurity http) throws Exception { http .authorizeRequests() .anyRequest().authenticated() .and() .formLogin() .loginProcessingUrl("/login"); 

感谢M. Denium,感谢本指南 ,我找到了解决方案。

首先,我遇到了登录表单本身的配置问题。 由于后端的上下文路径设置为/api ,自定义表单应该已将表格参数提交到/api/login但我实际上是将数据提交到/api/login/ (注意额外/最后)。

结果,我在不知不觉中试图访问受保护的资源! 因此,请求由默认的AuthenticationEntryPoint处理,默认行为是将用户重定向到登录页面。

作为解决方案,我实现了自定义AuthenticationEntryPoint:

 private AuthenticationEntryPoint authenticationEntryPoint() { return new AuthenticationEntryPoint() { @Override public void commence(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException { httpServletResponse.getWriter().append("Not authenticated"); httpServletResponse.setStatus(401); } }; } 

然后在配置中使用它:

 http .exceptionHandling() .authenticationEntryPoint(authenticationEntryPoint()) 

我为其他处理程序做了同样的事情:

 @Configuration @Order(SecurityProperties.ACCESS_OVERRIDE_ORDER) protected static class SecurityConfiguration extends WebSecurityConfigurerAdapter { @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.inMemoryAuthentication() .withUser("user").password("password").roles("ADMIN"); } @Override public void configure(HttpSecurity http) throws Exception { http .authorizeRequests() .anyRequest().authenticated() .and() .formLogin() .successHandler(successHandler()) .failureHandler(failureHandler()) .and() .exceptionHandling() .accessDeniedHandler(accessDeniedHandler()) .authenticationEntryPoint(authenticationEntryPoint()) .and() .csrf().csrfTokenRepository(csrfTokenRepository()).and().addFilterAfter(csrfHeaderFilter(), CsrfFilter.class) ; } private AuthenticationSuccessHandler successHandler() { return new AuthenticationSuccessHandler() { @Override public void onAuthenticationSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException { httpServletResponse.getWriter().append("OK"); httpServletResponse.setStatus(200); } }; } private AuthenticationFailureHandler failureHandler() { return new AuthenticationFailureHandler() { @Override public void onAuthenticationFailure(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException { httpServletResponse.getWriter().append("Authentication failure"); httpServletResponse.setStatus(401); } }; } private AccessDeniedHandler accessDeniedHandler() { return new AccessDeniedHandler() { @Override public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AccessDeniedException e) throws IOException, ServletException { httpServletResponse.getWriter().append("Access denied"); httpServletResponse.setStatus(403); } }; } private AuthenticationEntryPoint authenticationEntryPoint() { return new AuthenticationEntryPoint() { @Override public void commence(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException { httpServletResponse.getWriter().append("Not authenticated"); httpServletResponse.setStatus(401); } }; } private Filter csrfHeaderFilter() { return new OncePerRequestFilter() { @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { CsrfToken csrf = (CsrfToken) request.getAttribute(CsrfToken.class .getName()); if (csrf != null) { Cookie cookie = WebUtils.getCookie(request, "XSRF-TOKEN"); String token = csrf.getToken(); if (cookie == null || token != null && !token.equals(cookie.getValue())) { cookie = new Cookie("XSRF-TOKEN", token); cookie.setPath("/"); response.addCookie(cookie); } } filterChain.doFilter(request, response); } }; } private CsrfTokenRepository csrfTokenRepository() { HttpSessionCsrfTokenRepository repository = new HttpSessionCsrfTokenRepository(); repository.setHeaderName("X-XSRF-TOKEN"); return repository; } }