感谢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; }}


