PreAuthorize not working on Controller

£可爱£侵袭症+ 提交于 2019-11-26 22:51:15

问题


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 having ROLE_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.


回答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



回答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 {



回答3:


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




回答4:


For making it working on controller layer. I had to put @EnableAspectJAutoProxy on my configuration class. Example :

@Configuration
@EnableWebMvc
@EnableAspectJAutoProxy
@ComponentScan(basePackages = { "com.abc.fraud.ts.userservices.web.controller" })
public class WebConfig extends WebMvcConfigurerAdapter{

}



回答5:


put @EnableGlobalMethodSecurity(prePostEnabled = true) into MvcConfig class (extends WebMvcConfigurerAdapter) instead of (extends WebSecurityConfigurerAdapter).

Like below example:-

@EnableGlobalMethodSecurity(prePostEnabled = true)
public class MvcConfiguration extends WebMvcConfigurerAdapter {



回答6:


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);
}



回答7:


If you have a xml context file for your security beans and a separate one for your web/servlet context, than you als need to add:

<security:global-method-security pre-post-annotations="enabled"/>

to your web-context.xml / servlet context. Its not enough to just add it in the security context xml.

Its not inherited in child contexts.

HTH




回答8:


Hah,

I had the same proble and it was ,because my Controller`s methods were private ... ,they need to be public



来源:https://stackoverflow.com/questions/32442408/preauthorize-not-working-on-controller

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!