Main Tutorials

Spring Security : Customize 403 access denied page

In Spring Security, if non authorized user try to access a protected page, a default “http 403 access denied” will be displayed :

spring-security-403-default

In this tutorial, we will show you how to customize 403 access denied page in Spring Security.

1. Spring Security Configuration

Review a configuration, if “alex” try to access /admin page, above 403 access denied page will be displayed.

Spring-Security.xml

  <http auto-config="true">
	<access-denied-handler error-page="/403" />
	<intercept-url pattern="/admin**" access="ROLE_ADMIN" />
  </http>

  <authentication-manager>
	<authentication-provider>
	  <user-service>
		<user name="alex" password="123456" authorities="ROLE_USER" />
		<user name="mkyong" password="123456" authorities="ROLE_USER, ROLE_ADMIN" />
	  </user-service>
	</authentication-provider>
  </authentication-manager>

2. Solution – Customize 403 Page

2.1 Create a new 403 page.

403.jsp

<html>
<body>
	<h1>HTTP Status 403 - Access is denied</h1>
	<h2>${msg}</h2>
</body>
</html>

2.2. To display above page, add a error-page like the following :

Spring-Security.xml

	<http auto-config="true">
		<access-denied-handler error-page="/403" />
		<intercept-url pattern="/admin**" access="ROLE_ADMIN" />
	</http>

2.3 In a controller class, add a mapping for “/403” url :

HelloController.java

package com.mkyong.web.controller;

import java.security.Principal;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;

@Controller
public class HelloController {

	// for 403 access denied page
	@RequestMapping(value = "/403", method = RequestMethod.GET)
	public ModelAndView accesssDenied(Principal user) {

		ModelAndView model = new ModelAndView();

		if (user != null) {
			model.addObject("msg", "Hi " + user.getName() 
			+ ", you do not have permission to access this page!");
		} else {
			model.addObject("msg", 
			"You do not have permission to access this page!");
		}

		model.setViewName("403");
		return model;

	}

}

Done.

For annotation users, use this .exceptionHandling().accessDeniedPage("/403").

SecurityConfig.java

package com.mkyong.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

	@Override
	protected void configure(HttpSecurity http) throws Exception {

	 http.authorizeRequests()
	    .antMatchers("/admin/**").access("hasRole('ROLE_ADMIN')")
	    .and().formLogin()
		.loginPage("/login").failureUrl("/login?error")
		.usernameParameter("username")
		.passwordParameter("password")
	    .and().logout().logoutSuccessUrl("/login?logout")
	    .and()
		.exceptionHandling().accessDeniedPage("/403")
	}
}

3. AccessDeniedHandler

In additional, you can create a custom AccessDeniedHandler to perform some business logics before pass the URL to /403 mapping.

MyAccessDeniedHandler.java

package com.mkyong.web.exception;

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.web.access.AccessDeniedHandler;

public class MyAccessDeniedHandler implements AccessDeniedHandler {

	private String errorPage;

	public MyAccessDeniedHandler() {
	}

	public MyAccessDeniedHandler(String errorPage) {
		this.errorPage = errorPage;
	}

	public String getErrorPage() {
		return errorPage;
	}

	public void setErrorPage(String errorPage) {
		this.errorPage = errorPage;
	}

	@Override
	public void handle(HttpServletRequest request, HttpServletResponse response,
		AccessDeniedException accessDeniedException) 
                throws IOException, ServletException {

		//do some business logic, then redirect to errorPage url
		response.sendRedirect(errorPage);

	}

}

Add a ref to http tag.

Spring-Security.xml

	<http auto-config="true">
		<access-denied-handler ref="my403" />
		<intercept-url pattern="/admin**" access="ROLE_ADMIN" />
	</http>

	<beans:bean id="my403"
		class="com.mkyong.web.exception.MyAccessDeniedHandler">
		<beans:property name="errorPage" value="403" />
	</beans:bean>

Done.

4. Demo

When “alex” try to access /admin page, above customizing 403 access denied page will be displayed.

4.1 If using error-page, url will be displayed like this :

http://localhost:8080/spring-security-403-access-denied/admin

spring-security-403-example1

4.2 If using custom access denied handler ref, url will be displayed like this :

http://localhost:8080/spring-security-403-access-denied/403

spring-security-403-example2

Download Source Code

Download it – spring-security-403-access-denied.zip (26 KB)

References

  1. StackOverflow : How to handle HTTP 403 with Spring Security 3.0.x
  2. Spring Security : AccessDeniedHandler Reference

About Author

author image
Founder of Mkyong.com, love Java and open source stuff. Follow him on Twitter. If you like my tutorials, consider make a donation to these charities.

Comments

Subscribe
Notify of
23 Comments
Most Voted
Newest Oldest
Inline Feedbacks
View all comments
chris
6 years ago

I used the same exceptionhandling.accessDeniedPage() method but it doesn’t work. When I try to access a 403 page, I get redirected to the login page, I think it might be because I called the formlogin() method? Do you have any idea on how to solve this?

Many thanks!

Dhawal
4 years ago

Is there any way to get requested Controller in AccessDeniedHandler. I need this because I need different action for different Controller.

Cristin
6 years ago

This is exactly the kind of HOW NOT TO tutorial. Downloaded the project, doesn’t work. The author just copy pastes some code, doesn’t explain anything and when the user tries to run the demo, he has no idea where the problem is.

cc69cc
8 years ago

How solver the follow? If you send a null credential, spring security reconize that like valid (because is not void) but in some place is going to crash!

sdgian
9 years ago

How about the “return url”? How to pass the url of the resource that I want to access in the firts place once the auth process is done correctly?

xiaoyu
9 years ago

thanks for your article, i want to display the access denied page when there is an access denied in method security level(by using the preauthorize annotation), but your method doesn’t work, could you help me find out the answer? thank you

Gary
7 years ago
Reply to  xiaoyu

Thanks for the article, our team is having the same problem with preauthorize, can @mkyong:disqus you please help?

Guest
10 years ago

It’s a error?

I changed it to

It works well, so I think whether it’s a error? Any One know?

mkyong
9 years ago
Reply to  Guest

Sorry for the typo, Article is updated, please get the latest source code to test. Thanks.

Radhe
11 years ago

I don’t think creating handler and implementing it is good way.

You can just simply declare access deniedpage and your work done!!!!…
Thanks,
Radhe

mkyong
9 years ago
Reply to  Radhe

Agreed, error-page should be enough.

Radhe
11 years ago
Reply to  Radhe

Code snippet was removed. So, adding it!!!

<http auto-config="true" access-denied-page="/deniedpage"> 
IvoHaSp
11 years ago

Hi, is it right?

First you wrote:

The easiest way is uses “access-denied-handler‘ tag, and put your 403 page in “error-page” attribute :

but after that you mentioned 404 (a mistake?):

and correct it is:

Please, could you review attached zip file? I thing that many beginners like me have read this article they will a little disapoitmented.

Thank a lot Ivo.

mkyong
9 years ago
Reply to  IvoHaSp

Sorry for the typo, article is updated.

zecke
12 years ago

For this example you have forgot to display a controller, like this:


import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class ErrorController {
	@RequestMapping(value = "/403")
    public String accessDenied() {

          return "403"; // logical view name
     }

}


Please note you use a jsp-page. Without this controller you get an 404 error and a warning:
No mapping found for HTTP request with URI [/SpringMVC/403] in DispatcherServlet with name ‘mvc-dispatcher’

mkyong
9 years ago
Reply to  zecke

Article is updated, thanks for your inputs.

Bruce
11 years ago
Reply to  zecke

Thanks for your contribution

Haibin
12 years ago

I think another way to do it is to define

403
/403.jsp

in web.xml and webapp/403.jsp

Haibin
12 years ago
Reply to  Haibin
    <error-page>
        <error-code>403</error-code>
        <location>/403.jsp</location>
    </error-page>
Siddharth
11 years ago
Reply to  Haibin

Hello Haibin,

I have configured the webserver to display the error page where 404 is working fine but 403 is not working .

Is there any dependency in order to create 403 custom error page.I have used the below line to create custom error page

ErrorDocument 404 /404-page.html
ErrorDocument 403 /403-page.html

Waiting for your revert.

Regards,
Siddharth

Indravadan
12 years ago

Please changes the follwoing:

Without “/” against the 404, got the error.