[英]How to customize the 403 Forbidden/Access Denied Page using Spring Security
I'm a junior web developper and I need to customize the 403 error page using react js, I've found other projects implementing the AccessDeniedHandler interface but I don't know how to use it in my Security Configuration class.我是初级 web 开发人员,我需要使用 react js 自定义 403 错误页面,我发现其他项目实现了 AccessDeniedHandler 接口,但我不知道如何在我的安全配置 class 中使用它。
This is my CustomAccessDeniedHandler class:这是我的 CustomAccessDeniedHandler class:
@Component
public class CustomAccessDeniedHandler implements AccessDeniedHandler {
private static Logger logger = LoggerFactory.getLogger(CustomAccessDeniedHandler.class);
@Override
public void handle(HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse,
AccessDeniedException e) throws IOException, ServletException {
System.out.println("accessDenied");
Authentication auth
= SecurityContextHolder.getContext().getAuthentication();
if (auth != null) {
logger.info("User '" + auth.getName()
+ "' attempted to access the protected URL: "
+ httpServletRequest.getRequestURI());
}
httpServletResponse.sendRedirect(httpServletRequest.getContextPath() + "/accessDenied");
}
}
This is the Security Configuration class:这是安全配置 class:
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
AppUserService userDetailsService;
@Autowired
private AccessDeniedHandler accessDeniedHandler;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService);
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf()
.disable()
.exceptionHandling()
.authenticationEntryPoint(new Http403ForbiddenEntryPoint() {})
.and()
.authenticationProvider(getProvider())
.formLogin()
.loginPage("/login")
.successHandler(new AuthentificationLoginSuccessHandler())
.failureHandler(new SimpleUrlAuthenticationFailureHandler())
.and()
.logout()
.logoutUrl("/logout")
.logoutSuccessHandler(new AuthentificationLogoutSuccessHandler())
.invalidateHttpSession(true)
.and()
.authorizeRequests()
.antMatchers("/login").permitAll()
.antMatchers("/logout").permitAll()
.antMatchers("/api/categories").hasAuthority("USER")
.antMatchers("/api/createCategory").hasAuthority("ADMIN")
.anyRequest().permitAll();
}
private class AuthentificationLoginSuccessHandler extends SimpleUrlAuthenticationSuccessHandler {
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication)
throws IOException, ServletException {
response.setStatus(HttpServletResponse.SC_OK);
}
}
private class AuthentificationLogoutSuccessHandler extends SimpleUrlLogoutSuccessHandler {
@Override
public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response,
Authentication authentication) throws IOException, ServletException {
response.setStatus(HttpServletResponse.SC_OK);
}
}
@Bean
public AuthenticationProvider getProvider() {
AppAuthProvider provider = new AppAuthProvider();
provider.setUserDetailsService(userDetailsService);
return provider;
}
@Bean
public AccessDeniedHandler accessDeniedHandler(){
return new CustomAccessDeniedHandler();
}
}
What you have to do is to create @Bean
你要做的就是创建
@Bean
@Bean
public AccessDeniedHandler accessDeniedHandler(){
return new CustomAccessDeniedHandler();
}
which you already have and then add that handler in http security object like this:你已经有了,然后在 http security object 中添加该处理程序,如下所示:
http.csrf()
.disable()
.exceptionHandling()
.authenticationEntryPoint(new Http403ForbiddenEntryPoint() {}) //remove this line or use Http401UnauthorizedEntryPoint instead
.and()
.authenticationProvider(getProvider())
.formLogin()
.loginPage("/login")
.successHandler(new AuthentificationLoginSuccessHandler())
.failureHandler(new SimpleUrlAuthenticationFailureHandler())
.and()
.logout()
.logoutUrl("/logout")
.logoutSuccessHandler(new AuthentificationLogoutSuccessHandler())
.invalidateHttpSession(true)
.and()
.authorizeRequests()
.antMatchers("/login").permitAll()
.antMatchers("/logout").permitAll()
.antMatchers("/api/categories").hasAuthority("USER")
.antMatchers("/api/createCategory").hasAuthority("ADMIN")
.anyRequest().permitAll()
.and()
.exceptionHandling().accessDeniedHandler(accessDeniedHandler());
As you can see you are missing:如您所见,您缺少:
.and().exceptionHandling().accessDeniedHandler(accessDeniedHandler());
Additional, remove额外的,删除
@Autowired
private AccessDeniedHandler accessDeniedHandler;
because you shouldn't autowire bean, you should create it with custom implementation.因为您不应该自动装配 bean,所以您应该使用自定义实现来创建它。
EDIT: If you have @RestControllerAdvice
or @ControllerAdvice
as global exception handler you should do following:编辑:如果您有
@RestControllerAdvice
或@ControllerAdvice
作为全局异常处理程序,您应该执行以下操作:
@ExceptionHandler(Exception.class)
public ResponseEntity<?> exception(Exception exception) throws Exception {
if (exception instanceof AccessDeniedException) {
throw exception;
}
...
then it should work because when you throw exception it will go to custom handler which we do what you wrote.那么它应该可以工作,因为当你抛出异常时,它会将 go 发送到自定义处理程序,我们会按照你写的去做。 Also you can debug
ExceptionTranslationFilter
method handleSpringSecurityException
您也可以调试
ExceptionTranslationFilter
方法handleSpringSecurityException
code from ExceptionTranslationFilter
来自ExceptionTranslationFilter的代码
private void handleSpringSecurityException(HttpServletRequest request,
HttpServletResponse response, FilterChain chain, RuntimeException exception)
throws IOException, ServletException {
if (exception instanceof AuthenticationException) {
logger.debug(
"Authentication exception occurred; redirecting to authentication entry point",
exception);
sendStartAuthentication(request, response, chain,
(AuthenticationException) exception);
}
else if (exception instanceof AccessDeniedException) {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authenticationTrustResolver.isAnonymous(authentication) || authenticationTrustResolver.isRememberMe(authentication)) {
logger.debug(
"Access is denied (user is " + (authenticationTrustResolver.isAnonymous(authentication) ? "anonymous" : "not fully authenticated") + "); redirecting to authentication entry point",
exception);
sendStartAuthentication(
request,
response,
chain,
new InsufficientAuthenticationException(
messages.getMessage(
"ExceptionTranslationFilter.insufficientAuthentication",
"Full authentication is required to access this resource")));
}
else {
logger.debug(
"Access is denied (user is not anonymous); delegating to AccessDeniedHandler",
exception);
accessDeniedHandler.handle(request, response,
(AccessDeniedException) exception);
}
}
}
where you can see that accessDeniedHandler.handle(request, response,(AccessDeniedException) exception);
在那里你可以看到
accessDeniedHandler.handle(request, response,(AccessDeniedException) exception);
, in you case CustomAccessDeniedHandler
, get called. ,在你的情况下
CustomAccessDeniedHandler
,被调用。
I just tried it and it is working fine with (I have @ControllerAdvice
as global exception handler)我刚刚尝试过它并且它工作正常(我有
@ControllerAdvice
作为全局异常处理程序)
EDIT2: You have to remove this line EDIT2:你必须删除这一行
.authenticationEntryPoint(new Http403ForbiddenEntryPoint() {})
from SecurityConfig
, or change it to use Http401UnauthorizedEntryPoint
instead.来自
SecurityConfig
,或将其更改为使用Http401UnauthorizedEntryPoint
。 This is the problem in your case.这是你的问题。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.