Как требовать нескольких ролей / полномочий
Насколько я могу судить, любой из списков доступен в @Secured
аннотации или ExpressionUrlAuthorizationConfigurer
объекты. Попытка добавить несколько аннотаций или hasAuthority()
звонки либо не компилируются, либо используется только последний.
Как определить, что для конкретного запроса (набора запросов, соответствующего шаблону) или метода требуется весь список ролей / полномочий?
6 ответов
Лучшее решение, кажется,
@PreAuthorize("hasRole('one') and hasRole('two') and ...")
Там нет хорошего способа использовать константы, как с @Secured
,
Вы, кажется, используете: hasAuthority([authority])
, Это займет всего одну власть. Вместо этого используйте hasAnyAuthority([authority1,authority2])
, Это позволяет указывать несколько прав доступа одновременно, и любые из них могут учитываться при авторизации. Ссылка на официальные весенние документы здесь. Просто найдите на странице текст: hasAnyAuthority([authority1,authority2])
Например, в вашем методе контроллера добавьте: @PreAuthorize("hasAnyAuthority('permission1','permission2')")
Начиная с Spring Security 5.8, Spring обеспечивает поддержку композиции AuthorizationManager с помощьюAuthorizationManagers
сорт.
Благодаря этому мы можем определитьHttpSecurity
следующее:
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.authorizeHttpRequests(authorize -> authorize
.requestMatchers(HttpMethod.GET, "/my-endpoint")
.access(AuthorizationManagers.allOf(
AuthorityAuthorizationManager.hasAuthority(("SCOPE_one")),
AuthorityAuthorizationManager.hasAuthority("SCOPE_two")))
.anyRequest()
.authenticated());
return http.build();
}
Конечно, используйте статический импорт, чтобы представить конфигурацию в более понятном виде. Я включил сюда классы для ясности.
С Spring Security 5.5 вы можете использовать пользовательскийAuthorizationManager
при использованииAuthorizeHttpRequestsConfigurer
.
public class DelegatingMultiAuthorizationManager<T> implements AuthorizationManager<T> {
private final List<AuthorizationManager<T>> authorizationManagers;
public DelegatingMultiAuthorizationManager(List<AuthorizationManager<T>> authorizationManagers) {
this.authorizationManagers = authorizationManagers;
}
public static <T> DelegatingMultiAuthorizationManager<T> hasAll(AuthorizationManager<T>... authorizationManagers) {
Assert.notEmpty(authorizationManagers, "authorizationManagers cannot be empty");
Assert.noNullElements(authorizationManagers, "authorizationManagers cannot contain null values");
return new DelegatingMultiAuthorizationManager(Arrays.asList(authorizationManagers));
}
@Override
public AuthorizationDecision check(Supplier<Authentication> authentication, T object) {
for (AuthorizationManager<T> authorizationManager : authorizationManagers) {
AuthorizationDecision decision = authorizationManager.check(authentication, object);
if (decision == null || !decision.isGranted()) {
return new AuthorizationDecision(false);
}
}
return new AuthorizationDecision(true);
}
}
Этот AuthorizationManager требует, чтобы каждый предоставленный AuthorizationManager предоставлял доступ. Если какой-либо из них не предоставит доступ, авторизация не будет выполнена.
Затем вы можете использовать его следующим образом (что также позволяет использовать константы):
http.authorizeHttpRequests(authorize -> authorize
.antMatchers("/something/*")
.access(DelegatingMultiAuthorizationManager
.hasAll(AuthorityAuthorizationManager.hasAuthority("auth_a"),
AuthorityAuthorizationManager.hasAuthority("auth_b")))
В качестве решения для всей конечной точки вы можете просто использовать
.antMatchers("/user/**").access("hasAuthority('AUTHORITY_1') and hasAuthority('AUTHORITY_2')")
Я тестировал его только с двумя авторитетами, но, полагаю, вы можете и с более чем двумя.
Вы можете использовать
hasAnyAuthority
подобно
.hasAnyAuthority("manager", "customer");