37

I want my controller to return the right HTTP response code when the user lacks permission to view a particular page.

Oktay Alizada
  • 290
  • 1
  • 6
  • 19
Will Harris
  • 21,597
  • 12
  • 64
  • 64

6 Answers6

57

You can also just throw

org.springframework.security.access.AccessDeniedException("403 returned");

This returns a 403 in the response header.

Chris Ritchie
  • 4,749
  • 2
  • 36
  • 33
  • 1
    This works perfectly and should be the accepted answer because it's most flexible. – Heady Oct 19 '16 at 21:38
  • 3
    @Heady : Not really the best answer because it creates a strong dependency with Spring Security. Joe's answer, to create your own Exception, is the best IMO. I still upvoted that one since it's a decent alternative. – Guillaume F. Aug 22 '17 at 14:31
  • 9
    This returns a 500 for me. – heez Jan 13 '18 at 23:26
53

Create an Exception annotated with @ResponseStatus e.g. like this:

@ResponseStatus(HttpStatus.FORBIDDEN)
public class ForbiddenException extends RuntimeException {
}

Now just throw that Exception in your handler method and the response will have status 403.

yankee
  • 38,872
  • 15
  • 103
  • 162
  • See the [answer](https://stackoverflow.com/a/72009693/2160440) from @Largos below if you are using Spring 5+ – wlnirvana Jul 30 '22 at 14:19
13

Quickie

If you are using plain JSP views (as is most common), then simply add

<% response.setStatus( 403 ); %>

somewhere in your view file. At the top is a nice place.

Detail

In MVC, i would always set this in the view, and in most cases with Spring-MVC, use the SimpleMappingExceptionResolver to present the correct view in response to a thrown runtime Exception.

For example: create and throw a PermissionDeniedException in your controller or service layer and have the exception resolver point to a view file permissionDenied.jsp. This view file sets the 403 status and shows the user an appropriate message.

In your Spring bean XML file:

<bean id="exceptionResolver"
      class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
  <property name="exceptionMappings">
    <props>
      <prop key="PermissionDeniedException">          
        rescues/permissionDenied
      </prop>
      ... set other exception/view mappings as <prop>s here ...
    </props>
  </property>
  <property name="defaultErrorView" value="rescues/general" />
</bean>

<bean id="viewResolver"
      class="org.springframework.web.servlet.view.InternalResourceViewResolver">
  <property name="viewClass" value="org.springframework.web.servlet.view.JstlView" />
  <property name="prefix" value="/WEB-INF/views/" />
  <property name="suffix" value=".jsp" />
</bean>

If you need to implement a user login mechanism, take a look at Spring Security (formerly Acegi Security).

Cheekysoft
  • 35,194
  • 20
  • 73
  • 86
  • Why is the response.setStatus necessary? Following the response (in Tomcat), there seems to be some strage evolution of the http response code of the response - it is first 200 (default), then moves to 404 (for the sake of the argument) when the Spring DispatcherServlet process the handler exception, then, the view is rendered and the code is set to 500 (which is strange), and then, the setStatus does indeed fix the issue by reverting the code of the response back to 404. – Eugen Aug 08 '11 at 14:20
13

Using an ExceptionResolver is a great way to go, but if you just want this to be view-independent, you could certainly make a call to response.sendError(HttpServletResponse.SC_FORBIDDEN, "AdditionalInformationIfAvailable"); in your Controller.

Joe Liversedge
  • 4,124
  • 26
  • 19
10

Use ResponseStatusException :

@GetMapping("/demo")
public String demo(){
  if (forbidden){
    throw new ResponseStatusException(HttpStatus.FORBIDDEN); 
  }
}
Largos
  • 101
  • 1
  • 3
7

Use this: response.setStatus(403).

Michu93
  • 5,058
  • 7
  • 47
  • 80
John Boker
  • 82,559
  • 17
  • 97
  • 130