it-roy-ru.com

Spring Security, аннотация безопасности метода (@Secured) не работает (конфигурация Java)

Я пытаюсь настроить аннотацию безопасности метода с помощью @Secured («ADMIN») (без какого-либо XML, только конфигурация Java, Spring Boot). Но доступ через роли не работает.

Конфигурация безопасности:

@Configuration
@EnableWebSecurity
public class AppSecurityConfiguration extends WebSecurityConfigurerAdapter{

.....

@Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .authorizeRequests()
                .antMatchers("/api/**").fullyAuthenticated().and()
                .addFilterBefore(tokenAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
    }

.....

}

Я хочу ограничить доступ к методу контроллера:

@RestController
@RequestMapping("/api/groups")
public class GroupController {

    @Autowired
    private GroupService groupService;

    @Secured("ADMIN")
    @RequestMapping
    public List<Group> list() {
        return groupService.findAll();
    }

}

Ограничить доступ по URL работает, с помощью:

.antMatchers("/api/**").hasAuthority("ADMIN")

Может быть, я забыл указать, что я хочу ограничить по ролям?

UPD: По правилам, на каком уровне должна быть @PreAuthorize("hasRole('ADMIN')") на уровне контроллера или на уровне службы?

13
silverhawk

Эта проблема была решена.

Я добавляю @EnableGlobalMethodSecurity(prePostEnabled = true)

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

И в контроллере я изменил @Secured("ADMIN") на @PreAuthorize("hasRole('ADMIN')")

1
silverhawk

Пожалуйста, добавьте это 

@EnableGlobalMethodSecurity(securedEnabled = true)

Этот элемент используется для включения защиты на основе аннотаций в вашем приложении (путем установки соответствующих атрибутов для элемента), а также для группировки объявлений точки безопасности, которые будут применены ко всему контексту приложения специально для @Secured. Следовательно, ваш код должен выглядеть так

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled = true)
public class AppSecurityConfiguration extends WebSecurityConfigurerAdapter{..
24
Mudassar

Может быть много причин, по которым безопасность метода на контроллере не работает.

Во-первых, потому что это никогда не упоминается в качестве примера в руководстве по безопасности Spring ... шутка, но может быть сложно взять инструменты Spring там, где они не хотят идти.

Более серьезно, вы должны включить защиту метода, как уже сказано @Mudassar. В руководстве сказано:

Мы можем включить защиту на основе аннотаций, используя аннотацию @EnableGlobalMethodSecurity для любого экземпляра @Configuration. Например, следующее позволит включить аннотацию Spring Security @Secured.

@Configuration
@EnableGlobalMethodSecurity(securedEnabled = true)
public class MethodSecurityConfig {
   // ...
}

Обратите внимание, что ответ Мудассара верен до сих пор.

Но метод защиты основан на AOP, который по умолчанию использует JDK-прокси на interfaces . Вот почему во всех примерах применяется метод защиты на уровне сервиса, потому что классы сервиса обычно внедряются в контроллеры как интерфейсы.

Конечно, вы можете использовать его на уровне контроллера, но:

  • либо все ваши контроллеры реализуют интерфейсы для вас все @Secured аннотированные методы
  • или вы должны переключиться на проксирование классов

Правило, которому я стараюсь следовать:

  • если я хочу защитить URL, я придерживаюсь HTTPSecurity
  • если мне нужно разрешить более тонкий доступ, я добавляю безопасность на уровне сервиса
12
Serge Ballesta

Я знаю, что эта ветка довольно старая, и мой ответ ссылается на части ответов различных людей в этой ветке; но вот список, объединенный список подводных камней и ответов:

  1. При использовании @Secured имя роли (например, ADMIN); это означает аннотацию @Secured («ROLE_ADMIN»).
  2. WebSecurityConfigurerAdapter должен иметь @EnableGlobalMethodSecurity (securedEnabled = true)
  3. Как и в большинстве связанных с Spring прокси, убедитесь, что класс и защищенные методы ни в коем случае не являются окончательными. Для Kotlin это означает «открыть» каждый метод, а также класс.
  4. Когда класс и его методы являются виртуальными («открытыми»), то нет никакой подразумеваемой необходимости в интерфейсе.

Вот часть рабочего примера Kotlin:

@RestController
@RequestMapping("api/v1")

    open class DiagnosticsController {
        @Autowired
        lateinit var systemDao : SystemDao

        @RequestMapping("ping", method = arrayOf(RequestMethod.GET))
        @Secured("ROLE_ADMIN")
        open fun ping(request : HttpServletRequest, response: HttpServletResponse) : String { ... 
    }

а также

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled = true)
open class WebSecurityConfig : WebSecurityConfigurerAdapter() {

С уважением

8
user1210708

Вам нужно использовать @secured (ROLE_ADMIN) вместо @secured (ADMIN). Вы должны написать "ROLE_" перед именем вашей роли. Найдите приведенный ниже пример, который гарантирует, что только пользователь с ролью администратора может получить доступ к методу list ().

@RestController
@RequestMapping("/api/groups")
public class GroupController {

    @Autowired
    private GroupService groupService;

    @Secured("ROLE_ADMIN")
    @RequestMapping
    public List<Group> list() {
        return groupService.findAll();
    }

}
1
Sadiq Ali

Я хочу поделиться своим решением, может быть, оно будет полезным.

Используется Пружина MVC + Пружина безопасности , версия 4.2.9.RELEASE

Например, у меня есть служба с аннотированным методом @Secured 

@Secured("ACTION_USER_LIST_VIEW")
List<User> getUsersList();

Но это не сработало, потому что GlobalMethodSecurityConfiguration имеет метод inside.

protected AccessDecisionManager accessDecisionManager()

в котором инициализирован new RoleVoter() по умолчанию rolePrefix = "ROLE_";(это делает невозможным использование bean-компонентов для установки вашего rolePrefix), которые дают нам не работающие аннотации, потому что RoleVoter ожидает значение аннотации, которое начинается с 'ROLE_'

Для решения этой проблемы я переопределить GlobalMethodSecurityConfiguration как это

@Configuration
@EnableGlobalMethodSecurity(securedEnabled = true)
public class AppMethodSecurityConfiguration extends GlobalMethodSecurityConfiguration {
    @Override
    protected AccessDecisionManager accessDecisionManager() {
        List<AccessDecisionVoter<? extends Object>> decisionVoters = new ArrayList<>();
        ExpressionBasedPreInvocationAdvice expressionAdvice = new ExpressionBasedPreInvocationAdvice();
        expressionAdvice.setExpressionHandler(getExpressionHandler());
        decisionVoters.add(getRoleVoter());
        decisionVoters.add(new AuthenticatedVoter());
        return new AffirmativeBased(decisionVoters);
    }

    private RoleVoter getRoleVoter() {
        RoleVoter e = new RoleVoter();
        e.setRolePrefix("");
        return e;
    }
}
0
Igor

Возможно, вам следует зарегистрировать вашу AppSecurityConfiguration в том же контексте, что и WebMvcConfig (который расширяет WebMvcConfigurerAdapter).

AnnotationConfigWebApplicationContext mvcContext = new AnnotationConfigWebApplicationContext();      
mvcContext.register(WebMvcConfig.class, SecurityConfig.class);
0
digz6666