Spring Security - Creating 403 Access Denied User Response

I have a w760> boot rest api with jwt authentication. The problem is that I cannot get rid of the default 403 Access Denied rest answer, which looks like this:

{ "timestamp": 1516206966541, "status": 403, "error": "Forbidden", "message": "Access Denied", "path": "/api/items/2" } 

I created a custom AccessDeniedHandler:

 public class CustomAccessDeniedHandler implements AccessDeniedHandler { @Override public void handle(HttpServletRequest req, HttpServletResponse res, AccessDeniedException accessDeniedException) throws IOException, ServletException { ObjectMapper mapper = new ObjectMapper(); res.setContentType("application/json;charset=UTF-8"); res.setStatus(403); res.getWriter().write(mapper.writeValueAsString(new JsonResponse() .add("timestamp", System.currentTimeMillis()) .add("status", 403) .add("message", "Access denied"))); } } 

and added it to the webconfig class

 @EnableWebSecurity public class WebSecurity extends WebSecurityConfigurerAdapter { private UserDetailsService userDetailsService; private BCryptPasswordEncoder bCryptPasswordEncoder; @Autowired public WebSecurity(UserDetailsService userDetailsService, BCryptPasswordEncoder bCryptPasswordEncoder) { this.userDetailsService = userDetailsService; this.bCryptPasswordEncoder = bCryptPasswordEncoder; } @Override protected void configure(HttpSecurity http) throws Exception { http .sessionManagement() .sessionCreationPolicy(SessionCreationPolicy.NEVER) .and() .csrf().disable() .authorizeRequests() .antMatchers(HttpMethod.POST, REGISTER_URL).permitAll() .anyRequest().authenticated() .and() .exceptionHandling().accessDeniedHandler(accessDeniedHandler()) .and() .addFilter(new JWTAuthenticationFilter(authenticationManager(), tokenProvider())) .addFilter(new JWTAuthorizationFilter(authenticationManager(), tokenProvider())); } @Override public void configure(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder); } @Bean public TokenProvider tokenProvider(){ return new TokenProvider(); } @Bean public AccessDeniedHandler accessDeniedHandler(){ return new CustomAccessDeniedHandler(); } } 

Despite this, I still get a default rejection response. When debugging, I realized that the handle method from the user exit was not even called. What's going on here?

+8
source share
4 answers

I think I solved the problem. Instead of creating an AccessDeniedHandler implementation, I had to create a custom AuthenticationEntryPoint and set it in exception handling.

WebConfig now looks like this:

 @EnableWebSecurity public class WebSecurity extends WebSecurityConfigurerAdapter { private UserDetailsService userDetailsService; private BCryptPasswordEncoder bCryptPasswordEncoder; @Autowired public WebSecurity(UserDetailsService userDetailsService, BCryptPasswordEncoder bCryptPasswordEncoder) { this.userDetailsService = userDetailsService; this.bCryptPasswordEncoder = bCryptPasswordEncoder; } @Override protected void configure(HttpSecurity http) throws Exception { http .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) .and() .csrf().disable() .authorizeRequests() .antMatchers(HttpMethod.POST, REGISTER_URL).permitAll() .anyRequest().authenticated() .and() .exceptionHandling().authenticationEntryPoint(authenticationEntryPoint()) .and() .addFilter(new JWTAuthenticationFilter(authenticationManager(), tokenProvider())) .addFilter(new JWTAuthorizationFilter(authenticationManager(), tokenProvider())); } @Override public void configure(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder); } @Bean public TokenProvider tokenProvider(){ return new TokenProvider(); } @Bean public AuthenticationEntryPoint authenticationEntryPoint(){ return new CustomAuthenticationEntryPoint(); } } 

and CustomAuthenticationEntryPoint:

 public class CustomAuthenticationEntryPoint implements AuthenticationEntryPoint { @Override public void commence(HttpServletRequest req, HttpServletResponse res, AuthenticationException authException) throws IOException, ServletException { res.setContentType("application/json;charset=UTF-8"); res.setStatus(403); res.getWriter().write(JsonBuilder //my util class for creating json strings .put("timestamp", DateGenerator.getDate()) .put("status", 403) .put("message", "Access denied") .build()); } } 

Now everything works the way I wanted.

0
source

I have the same problem and tried to solve it correctly, but this does not solve the problem. The best way to handle this is to implement a denied access handler. The AuthenticationEntryPoint implementation is best handled by 401, UNAUTHORIZED access, and the AccessDeniedHandler implementation exists for 403, FORBIDDEN access.

Override the AccessDeniedHandler method in your implementation class as follows:

 @Override public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException { response.getWriter().write("Access Denied... Forbidden"); } 

And add this denied access handler to your security configuration code as follows:

 .exceptionHandling() .authenticationEntryPoint(authenticationEntryPoint()) .accessDeniedHandler(accessDeniedHandler()) 
+1
source

Here is a minimal security configuration that demonstrates that a custom AccessDeniedHandler is invoked in access denied scripts (403):

 @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http .authorizeRequests() .antMatchers("/css/**", "/index").permitAll() .antMatchers("/admin/**").hasRole("ADMIN") .antMatchers("/user/**").hasRole("USER") .and() .formLogin() .and() .exceptionHandling() .accessDeniedHandler((request, response, accessDeniedException) -> { AccessDeniedHandler defaultAccessDeniedHandler = new AccessDeniedHandlerImpl(); defaultAccessDeniedHandler.handle(request, response, accessDeniedException); }); } @Autowired public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { auth .inMemoryAuthentication() .withUser(User.withDefaultPasswordEncoder().username("user").password("password").roles("USER")) .withUser(User.withDefaultPasswordEncoder().username("admin").password("password").roles("ADMIN")); } } 

Playback Actions:

  1. Login using user/password
  2. Try to access http://localhost:8080/user/index - access granted
  3. Try to access http://localhost:8080/admin/index - access is denied and AccessDeniedHandler custom AccessDeniedHandler
0
source

In accordance with this:

http://www.baeldung.com/spring-security-custom-access-denied-page

You also need to add:

.exceptionHandling () accessDeniedHandler (accessDeniedHandler ()) ;.

guess what goes to "configure".

-2
source

Source: https://habr.com/ru/post/1274771/


All Articles