自定义登录表单。 配置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; } }