PreAuthorize not working on Controller
Solution 1
A common problem with using PrePost annotations on controllers is that Spring method security is based on Spring AOP, which is by default implemented with JDK proxies.
That means that it works fine on the service layer which is injected in controller layer as interfaces, but it is ignored on controller layer because controller generally do not implement interfaces.
The following is just my opinion:
- prefered way: move the pre post annotation on service layer
- if you cannot (or do not want to), try to have your controller implement an interface containing all the annotated methods
- as a last way, use proxy-target-class=true
Solution 2
You have to add @EnableGlobalMethodSecurity(prePostEnabled = true)
in your WebSecurityConfig.
You can find it here: http://www.baeldung.com/spring-security-expressions-basic
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
Solution 3
put @EnableGlobalMethodSecurity(prePostEnabled = true) into MvcConfig class (extends WebMvcConfigurerAdapter) instead of (extends WebSecurityConfigurerAdapter).
Like below example:-
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class MvcConfiguration extends WebMvcConfigurerAdapter {
Solution 4
I had a similar problem and the following solved it:
1) I had to make my method public (i.e. make your method home() public)
2) I have to use hasRole instead of hasAuthority
Solution 5
There are two different ways to use this, one is to prefix and one is not.
And you maybe change @PreAuthorize("hasAuthority('ROLE_ADMIN')")
to @PreAuthorize("hasAuthority('ADMIN')")
will be ok.
next is @PreAuthorize
source code.
private String defaultRolePrefix = "ROLE_";
public final boolean hasAuthority(String authority) {
return hasAnyAuthority(authority);
}
public final boolean hasAnyAuthority(String... authorities) {
return hasAnyAuthorityName(null, authorities);
}
public final boolean hasRole(String role) {
return hasAnyRole(role);
}
public final boolean hasAnyRole(String... roles) {
return hasAnyAuthorityName(defaultRolePrefix, roles);
}
Comments
-
prettyvoid over 2 years
I'm trying to define access rules at method-level but it's not working what so ever.
SecurityConfiguration
@Configuration @EnableWebSecurity @EnableGlobalMethodSecurity(prePostEnabled = true) public class SecurityConfiguration extends WebSecurityConfigurerAdapter { @Override public void configure(AuthenticationManagerBuilder auth) throws Exception { auth.inMemoryAuthentication(). withUser("user").password("user").roles("USER").and(). withUser("admin").password("admin").roles("ADMIN"); } @Override protected void configure(HttpSecurity http) throws Exception { http .sessionManagement() .sessionCreationPolicy(SessionCreationPolicy.STATELESS) .and() .authorizeRequests() .antMatchers("/v2/**").authenticated() .and() .httpBasic() .realmName("Secure api") .and() .csrf() .disable(); } }
ExampleController
@EnableAutoConfiguration @RestController @RequestMapping({"/v2/"}) public class ExampleController { @PreAuthorize("hasAuthority('ROLE_ADMIN')") @RequestMapping(value = "/home", method = RequestMethod.GET) String home() { return "Hello World"; } }
Whenever I try to access /v2/home using
user:user
it executes just fine, shouldn't it give me an Access Denied error due to 'user' not havingROLE_ADMIN
?I'm actually thinking of ditching access rules at method-level and stick to http() ant rules, but I have to know why it's not working for me.
-
prettyvoid over 8 yearsThanks for the answer. I've tried using the annotation on a
CrudRepository
interface and it worked fine. Having an interface to each controller is kinda silly in my opinion as an interface isn't really necessary.proxy-target-class=true
didn't make a difference, the annotations still doesn't work on controllers, however it caused a crash (while set to true) when having the annotation inside the repository interface (Cannot subclass com.sun.proxy). Anyway I think I'm going to stick to rules in the security config, and maybe use PreAuth on some of my repositories. -
prettyvoid over 8 yearsOne other thing that I noticed, I've seen examples where the @PreAuthorize was used in a
class
instead of aninterface
and it's supposed to be working.. I wonder why it works for them but not for me. -
Rudolf Schmidt about 8 yearsI had the same issue and making the methods public solved it!
-
Mradul Pandey almost 8 yearsEnable Aop in application context <aop:aspectj-autoproxy />
-
Kieveli almost 8 yearsAdding the interface fixed it for me, but another project doesn't have interfaces, and the controller methods are protected. There must be some other configuration that they're using that I'm not.
-
An Nguyen almost 8 yearsI am facing the same issue but opposite. @PreAuthorize works normal on controller layer but not on service layer. Do you know why?
-
Piyush over 6 yearsmaking the controller methods public solved it for me.
-
valik over 6 yearsand this source should be added where and how does my controller access it ?
-
valik over 6 yearsmine worked without this @EnableAspectJAutoProxy I just used @PreAuthorize("hasAuthority('ADMIN')")
-
valik over 6 yearswhy is that? @kripal kashyav
-
Dherik over 6 yearsI had weird problems using @PreAuthorize on Controller: some applications works well and some applications don't.
-
GameSalutes almost 6 yearsAlso per previous commenter if putting pre/post on a controller method that does not implement an interface also add annotation property
proxyTargetClass = true
toEnableGlobalMethodSecurity
-
Stefan Falk over 5 yearsDoes not work for me unfortunately (see stackoverflow.com/questions/53125388/…).
-
beautifulcode over 5 yearsThe problem of the ExampleController, only changed ROLE_ADMIN to ADMIN
-
Krzysztof Skrzynecki over 4 yearsOP did it already using
@EnableGlobalMethodSecurity(prePostEnabled = true)
-
Arshad Ali about 4 yearsI tried as you suggested it works fine, but what is the correct way of implementing
hasRole
clause like@PreAuthorize("hasRole('ADMIN')")
-
Wecherowski over 3 yearshas this been changed by now? Because the prePost annotations work absolutely fine on my controllers without implementing any interface or allowing target class proxying
-
AreUMinee over 3 yearsChanging the method from private to public worked for me.
-
anavaras lamurep almost 3 yearsi 'm trying this for past one month , everything is correct , expect this public one ..hell of a learning. Finally found the problem. thanks @georgi Peev
-
Stanislau Listratsenka almost 2 yearsit worked for me, but can't image why