I'm new to building rest APi using spring boot.
Here is my controller
snippet
@PreAuthorize("hasRole('ADMIN')")
@PostMapping(value = "/api/post/posts", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<PostDto> createPost(@Valid @RequestBody PostDto postDto) {
System.out.println("postDto : " postDto.getId());
return new ResponseEntity<>(postService.createPost(postDto), HttpStatus.CREATED);
}
this is my Security
config
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true) //give method level security
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable().authorizeRequests().antMatchers(HttpMethod.GET, "/api/**").permitAll().anyRequest()
.authenticated().and().httpBasic();
}
@Override
@Bean
protected UserDetailsService userDetailsService() {
// In Memory Users
UserDetails ashish = User.builder().username("oxana").password(getPasswordEncoder().encode("password")).roles("USER").build();
UserDetails admin = User.builder().username("admin").password(getPasswordEncoder().encode("admin")).roles("ADMIN").build();
return new InMemoryUserDetailsManager(ashish, admin);
}
@Bean
PasswordEncoder getPasswordEncoder() {
return new BCryptPasswordEncoder();
}
}
I'm trying land above exception here
@ExceptionHandler(Exception.class)
public ResponseEntity<Errors> handleGlobalException(Exception exception,
WebRequest webRequest){
Error errorDetails = new Error();
errorDetails.setErrorDesc(exception.getMessage());
errorDetails.setErrorCode(Error.ErrorCodeEnum.BAD_REQUEST);
Errors errors = new Errors();
errors.addErrorsItem(errorDetails);
return new ResponseEntity<>(errors, HttpStatus.INTERNAL_SERVER_ERROR);
}
but its not coming and giving a big mess of error, like this
"timestamp": "2022-02-21T11:39:28.797 00:00",
"status": 403,
"error": "Forbidden",
"trace": "org.springframework.security.access.AccessDeniedException: Access is denied\r\n\tat org.springframework.security.access.vote.AffirmativeBased.decide(AffirmativeBased.java:73)\r\n\tat org.springframework.security.access.intercept.AbstractSecurityInterceptor.attemptAuthorization(AbstractSecurityInterceptor.java:238)\r\n\tat org.springframework.security.access.intercept.AbstractSecurityInterceptor.beforeInvocation(AbstractSecurityInterceptor.java:208)\r\n\tat org.springframework.security.access.intercept.aopalliance.
Can anyone please suggest me, How can I handle or catch this exception to customize error, where user has no access to do something ?
Thanks
Update
Implemented AccessDeniedHandler
in below way
@ResponseStatus(value = HttpStatus.FORBIDDEN, reason = "Dont have sufficient priviliges to perform this action")
public class AccessDeniedError implements AccessDeniedHandler {
@Override
public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException exec)
throws IOException, ServletException {
response.sendRedirect("Dont have sufficient priviliges to perform this action");
}
}
And now able to get message like this
{
"timestamp": "2022-02-21T13:29:08.377 00:00",
"status": 404,
"error": "Not Found",
"message": "No message available",
"path": "/api/post/Dont have sufficient priviliges to perform this action"
}
Its somewhat better, but how can I take control of these variables ("error", "message", "status")
values from above response, so that I could add mine custom values in it ?
CodePudding user response:
The AccessDeniedException
is handled by the ExceptionTranslationFilter
which then delegates to the AccessDeniedHandler
to write to corresponding response to the client.
If you want to customize this behavior, then you can implement a AccessDeniedHandler
and then set your implementation to the HttpSecurity
object.
MyAccessDeniedHandler.java
public class MyAccessDeniedHandler implements AccessDeniedHandler {
@Override
public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
writeCustomResponse(response);
}
private void writeCustomResponse(HttpServletResponse response) {
if (!response.isCommitted()) {
try {
response.getWriter().write("{ \"error\": \"User is not authorized.\"}");
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}
SecurityConfiguration.java
@Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// set the customized AccessDeniedHandler to the HttpSecurity object
http.exceptionHandling().accessDeniedHandler(new MyAccessDeniedHandler());
}
}