PreAuthorize не работает на контроллере

Я пытаюсь определить правила доступа на уровне метода, но он не работает так, как никогда.

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

Всякий раз, когда я пытаюсь получить доступ к /v 2/home с помощью user:user, он выполняется просто отлично, не должен ли он давать мне ошибку Access Denied из-за "пользователя", не имеющего ROLE_ADMIN?

Я на самом деле думаю о правилах доступа на уровне метода и придерживаюсь правил http() ant, но я должен знать, почему он не работает для меня.

Ответ 1

Общая проблема с использованием аннотаций PrePost на контроллерах заключается в том, что безопасность метода Spring основана на Spring AOP, который по умолчанию реализован с прокси-серверами JDK.

Это означает, что он отлично работает на уровне сервиса, который вводится в уровень контроллера как интерфейсы, но игнорируется на уровне контроллера, потому что контроллер обычно не реализует интерфейсы.

Вот только мое мнение:

  • предпочтительный способ: перенести аннотацию предварительной публикации на уровень обслуживания
  • Если вы не можете (или не хотите), попробуйте, чтобы ваш контроллер реализовал интерфейс, содержащий все аннотированные методы.
  • как последний способ, используйте proxy-target-class= true

Ответ 2

Вы должны добавить @EnableGlobalMethodSecurity(prePostEnabled = true) в свой WebSecurityConfig.

Вы можете найти его здесь: http://www.baeldung.com/spring-security-expressions-basic

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

Ответ 3

У меня была аналогичная проблема, и следующие ее решили:

1) Мне пришлось сделать мой метод общедоступным (т.е. сделать ваш метод home() общедоступным)

2) Мне нужно использовать hasRole вместо hasAuthority

Ответ 4

Для работы с контроллером. Мне пришлось поставить @EnableAspectJAutoProxy в свой класс конфигурации. Пример:

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

}

Ответ 5

Существует два разных способа использования: один - префикс, а другой - нет. И вы можете изменить @PreAuthorize("hasAuthority('ROLE_ADMIN')") на @PreAuthorize("hasAuthority('ADMIN')") будет нормально.

next - @PreAuthorize исходный код.

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

Ответ 6

Если у вас есть файл контекста xml для ваших компонентов безопасности и отдельный файл для контекста web/servlet, вам нужно добавить:

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

в ваш контекст web-context.xml/servlet. Недостаточно просто добавить его в контексте безопасности xml.

Его не наследуется в детском контексте.

НТН

Ответ 7

поместите @EnableGlobalMethodSecurity (prePostEnabled = true) в класс MvcConfig (расширяет WebMvcConfigurerAdapter) вместо (расширяет WebSecurityConfigurerAdapter).

Как пример ниже: -

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