Spring 安全性:在 401 情况下重定向到单页应用
Spring Security: redirect to single page app in case of 401
当我在浏览器中输入我的 React 应用程序的任何路由时,例如:http://localhost/login,请求到达我的服务器,我的服务器响应 401 未授权。
当请求不是授权后端时api我想在我的反应路由中处理请求。
WebSecurityConfig.java:
@Override
protected void configure(HttpSecurity http) throws Exception {
http
...
.formLogin()
.disable()
.authorizeRequests()
.antMatchers(
"/error",
"/",
"/favicon.ico",
"/static/**",
"/api/auth/**",
"/api/oauth2/**",
"/api/courses/**",
"/api/stripe/**",
"/api/lesson/content")
.permitAll()
.anyRequest()
.authenticated()
.and()
...
.exceptionHandling()
.authenticationEntryPoint(new RestAuthenticationEntryPoint())
.and();
http.addFilterBefore(tokenAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
}
RestAuthenticationEntryPoint.java:
public class RestAuthenticationEntryPoint implements AuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse,
AuthenticationException e) throws IOException, ServletException {
httpServletResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED,
e.getLocalizedMessage());
}
}
有没有办法在 RestAuthenticationEntryPoint 中将请求转发到 index.html?
你可以在 react 中处理一个 401
:
axios.post('http://localhost:8080/login', data)
.then(resp => ...)
.catch(e => {
if (e.response && e.response.status===401)
history.push('/error');
});
或者您可以修改您的 AuthenticationHandler
:
@Override
public void commence(HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse,
AuthenticationException e) throws IOException, ServletException {
httpServletResponse.sendRedirect("http://localhost:3000/error");
}
我决定从 RestAuthenticationEntryPoint 抛出 404 Not Found 异常,因为我认为它比 401 Unathorized 更符合这个用例:
@Override
public void commence(HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse,
AuthenticationException e) throws IOException, ServletException {
httpServletResponse.sendError(HttpServletResponse.SC_NOT_FOUND,
e.getLocalizedMessage());
}
并将找不到异常重定向到前端:
@Bean
public WebServerFactoryCustomizer<ConfigurableServletWebServerFactory> containerCustomizer() {
return container -> {
container.addErrorPages(new ErrorPage(HttpStatus.NOT_FOUND,
"/notFound"));
};
}
@Controller
public class CustomErrorController {
@ResponseStatus(HttpStatus.OK)
@RequestMapping(value = "/notFound")
public String error() {
return "forward:/index.html";
}
}
这种方法的缺点是我不能从任何控制器抛出 404,因为它不会返回到前端,但我可以接受。
当我在浏览器中输入我的 React 应用程序的任何路由时,例如:http://localhost/login,请求到达我的服务器,我的服务器响应 401 未授权。
当请求不是授权后端时api我想在我的反应路由中处理请求。
WebSecurityConfig.java:
@Override
protected void configure(HttpSecurity http) throws Exception {
http
...
.formLogin()
.disable()
.authorizeRequests()
.antMatchers(
"/error",
"/",
"/favicon.ico",
"/static/**",
"/api/auth/**",
"/api/oauth2/**",
"/api/courses/**",
"/api/stripe/**",
"/api/lesson/content")
.permitAll()
.anyRequest()
.authenticated()
.and()
...
.exceptionHandling()
.authenticationEntryPoint(new RestAuthenticationEntryPoint())
.and();
http.addFilterBefore(tokenAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
}
RestAuthenticationEntryPoint.java:
public class RestAuthenticationEntryPoint implements AuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse,
AuthenticationException e) throws IOException, ServletException {
httpServletResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED,
e.getLocalizedMessage());
}
}
有没有办法在 RestAuthenticationEntryPoint 中将请求转发到 index.html?
你可以在 react 中处理一个 401
:
axios.post('http://localhost:8080/login', data)
.then(resp => ...)
.catch(e => {
if (e.response && e.response.status===401)
history.push('/error');
});
或者您可以修改您的 AuthenticationHandler
:
@Override
public void commence(HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse,
AuthenticationException e) throws IOException, ServletException {
httpServletResponse.sendRedirect("http://localhost:3000/error");
}
我决定从 RestAuthenticationEntryPoint 抛出 404 Not Found 异常,因为我认为它比 401 Unathorized 更符合这个用例:
@Override
public void commence(HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse,
AuthenticationException e) throws IOException, ServletException {
httpServletResponse.sendError(HttpServletResponse.SC_NOT_FOUND,
e.getLocalizedMessage());
}
并将找不到异常重定向到前端:
@Bean
public WebServerFactoryCustomizer<ConfigurableServletWebServerFactory> containerCustomizer() {
return container -> {
container.addErrorPages(new ErrorPage(HttpStatus.NOT_FOUND,
"/notFound"));
};
}
@Controller
public class CustomErrorController {
@ResponseStatus(HttpStatus.OK)
@RequestMapping(value = "/notFound")
public String error() {
return "forward:/index.html";
}
}
这种方法的缺点是我不能从任何控制器抛出 404,因为它不会返回到前端,但我可以接受。