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 :
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.
<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.
<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 :
<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 :
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")
.
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.
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.
<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
4.2 If using custom access denied handler ref
, url will be displayed like this :
http://localhost:8080/spring-security-403-access-denied/403
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!
Is there any way to get requested Controller in AccessDeniedHandler. I need this because I need different action for different Controller.
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.
May I know what is not working?
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!
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?
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
Thanks for the article, our team is having the same problem with preauthorize, can @mkyong:disqus you please help?
It’s a error?
I changed it to
It works well, so I think whether it’s a error? Any One know?
Sorry for the typo, Article is updated, please get the latest source code to test. Thanks.
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
Agreed, error-page should be enough.
Code snippet was removed. So, adding it!!!
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.
Sorry for the typo, article is updated.
For this example you have forgot to display a controller, like this:
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’
Article is updated, thanks for your inputs.
Thanks for your contribution
I think another way to do it is to define
403
/403.jsp
in web.xml and webapp/403.jsp
Thanks for your additional input.
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
Please changes the follwoing:
Without “/” against the 404, got the error.