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

【字号: 日期:2024-03-22浏览:49作者:雯心
(adsbygoogle = window.adsbygoogle || []).push({}); 如何解决自定义登录表单配置Spring安全性以获取JSON响应?

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

首先,登录表单本身存在配置问题。由于后端将context-path设置为/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; }}解决方法

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

后端通过Spring-boot / Spring-security公开REST服务一个仅包含静态文件的前端。

Nginx服务器接收请求,该服务器监听端口80。

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

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

在很多示例中,我可以看到如何定义“登录成功” URL和“登录错误” URL,但是我不希望Spring-security重定向用户。如果登录成功或HTTP40x登录失败,我希望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');

相关文章: