Spring Boot: настроить пользовательские MethodSecurityExpressionOperations? - PullRequest
1 голос
/ 03 октября 2019

У меня проблемы со съемкой конфигурации безопасности с весенней загрузкой, которая когда-то работала, но теперь не распознает мои пользовательские определения. Моя цель состояла в том, чтобы защитить все наши Сервисы с помощью безопасности уровня метода в Spring с помощью пользовательских аннотаций.

Когда я запускаю сервис, создается экземпляр моего CustomMethodSecurityConfig, и он вызывает createExpressionHandler (), но когда я делаю запрос к сервисуон не вызывает createSecurityExpressionRoot (...) для моего CustomMethodSecurityExpressionHandler, но для DefaultWebSecurityExpressionHandler.

Я ценю любые идеи, которые кто-либо может предоставить, почему Spring Security не распознает мои выражения, определенные в моем CustomMethodSecurityExpression.

Вот фрагмент моего класса GlobalMethodSecurityConfiguration

@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class CustomMethodSecurityConfig extends GlobalMethodSecurityConfiguration {

  private final MyService1 myService1;
  private final MyService2 myService2;
  private final MyService3 myService3;

  @Autowired
  public CustomMethodSecurityConfig(MyService1 myService1, MyService2 myService2,
                                    MyService3 myService3) {
    this.myService1 = myService1;
    this.myService2 = myService2;
    this.myService3 = myService3;
  }

  @Override
  protected MethodSecurityExpressionHandler createExpressionHandler() {
    CustomMethodSecurityExpressionHandler expressionHandler =
        new CustomMethodSecurityExpressionHandler(myService1, myService2, myService3);
    expressionHandler.setPermissionEvaluator(permissionEvaluator());
    return expressionHandler;
  }
}

Вот фрагмент моего класса DefaultMethodSecurityExpressionHandler

public class CustomMethodSecurityExpressionHandler extends DefaultMethodSecurityExpressionHandler {

  private final MyService1 myService1;
  private final MyService2 myService2;
  private final MyService3 myService3;
  private AuthenticationTrustResolver trustResolver = new AuthenticationTrustResolverImpl();

  public CustomMethodSecurityExpressionHandler(MyService1 myService1, MyService2 myService2,
                                               MyService3 myService3) {
    this.myService1 = myService1;
    this.myService2 = myService2;
    this.myService3 = myService3;
  }

  @Override
  protected MethodSecurityExpressionOperations createSecurityExpressionRoot(Authentication authentication,
                                                                            MethodInvocation invocation) {
    CustomMethodSecurityExpressionRoot root = new CustomMethodSecurityExpressionRoot(authentication,
                                                                                     myService1,
                                                                                     myService2,
                                                                                     myService3);

    root.setPermissionEvaluator(getPermissionEvaluator());
    root.setTrustResolver(this.trustResolver);
    root.setRoleHierarchy(getRoleHierarchy());

    return root;
  }
}

Вот фрагмент моего SecurityExpressionRoot, этогде я определяю свои выражения SpEL, которые я использую в аннотациях к моим Сервисам. Я включил только упрощенный, isUser в качестве примера. То, что делают эти методы, не важно, но тот факт, что они видимы.

public class CustomMethodSecurityExpressionRoot extends SecurityExpressionRoot
    implements MethodSecurityExpressionOperations {

  private Object filterObject;
  private Object returnObject;

  private MyService1 myService1;
  private MyService2 myService2;
  private MyService3 myService3;

  public CustomMethodSecurityExpressionRoot(
      Authentication authentication,
      MyService1 myService1,
      MyService2 myService2,
      MyService3 myService3) {
    super(authentication);
    this.myService1 = myService1;
    this.myService2 = myService2;
    this.myService3 = myService3;
  }

  @Override
  public Object getFilterObject() {
    return this.filterObject;
  }

  @Override
  public Object getReturnObject() {
    return this.returnObject;
  }

  @Override
  public void setFilterObject(Object obj) {
    this.filterObject = obj;
  }

  @Override
  public void setReturnObject(Object obj) {
    this.returnObject = obj;
  }

  @Override
  public Object getThis() {
    return this;
  }

  //All custom SpEL methods
  public boolean isUser(Long userId) {
    SecurityUser user = (SecurityUser) this.getPrincipal();
    return user.getUserId() == userId;
  }

  ...

}

И, наконец, вот фрагмент моего WebSecurityConfigurerAdapter, который используется в тандеме, он проверяет маркер внешней аутентификации от нашего UAAserver.

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(
    prePostEnabled = true,
    proxyTargetClass = true)
public class ServiceSecurityConfig extends WebSecurityConfigurerAdapter {

  private final TokenCheckService _tokenCheckService;

  @Autowired
  ServiceSecurityConfig(TokenCheckService tokenCheckService) {
    _tokenCheckService = tokenCheckService;
  }

  @Override
  protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    auth.authenticationProvider(new TokenAuthenticationProvider(_tokenCheckService));
  }

  @Override
  public void configure(WebSecurity web) throws Exception {
    web.ignoring().antMatchers(HttpMethod.OPTIONS, "/api/**");
  }

  @Override
  protected void configure(HttpSecurity http) throws Exception {
        http
            .anonymous()
              .disable()
            .csrf()
              .disable()
            .exceptionHandling()
              .authenticationEntryPoint(new UnAuthorizedEntryPoint())
              .and()
            .sessionManagement()
              .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
              .and()
            .authorizeRequests()
              .anyRequest().authenticated();
    http.addFilterBefore(new AuthenticationTokenFilter(), BasicAuthenticationFilter.class);
  }
}

Редактировать: Кажется, я думаю, что это проблема с моими WebDecisionVoters, перезаписываемыми во время инициализации. Если у меня есть точка останова в конструкторе «Утверждение»

AffirmativeBased(List<AccessDecisionVoter<? extends Object>> decisionVoters)

, я вижу, как для AffirrativeBased создаются три участника голосования, одним из которых является PreInvocationAuthorizationAdviceVoter, который содержит ссылку на мой обработчик выражений. Я полагаю, что это создается созданием компонента bean метода methodSecurityInterceptor.

Когда я продолжаю точку останова, я снова обращаюсь к тому же конструктору, основанному на утверждениях, но только с одним избирателем принятия решения, WebExperssionVoter со ссылкой на экземпляр DefaultWebSecurityExpressionHandler. ,Я полагаю, что это создается созданием bean-компонента springSecurityFilterChain.

1 Ответ

0 голосов
/ 16 октября 2019

Мне удалось решить эту проблему, выполнив шаги в Пользовательское выражение SecurityExpression с сервисом . Кажется, проблема связана с моими автоматически подключенными службами, которые были отделены от безопасности. MyService1, MyService2 и MyService3, вызывающие проблемы и устраняющие их, позволяют работать безопасности.

Любые дополнительные службы должны быть установлены в createSecurityExpressionRoot класса, который расширяет DefaultMethodSecurityExpressionHandler.

@Override
protected MethodSecurityExpressionOperations createSecurityExpressionRoot(Authentication authentication, MethodInvocation invocation) {
    CustomMethodSecurityExpressionRoot root = new CustomMethodSecurityExpressionRoot(authentication);
    // Other initialization
    root.setMyService1(applicationContext.getBean(MyService1.class));
    root.setMyService2(applicationContext.getBean(MyService2.class));
    root.setMyService3(applicationContext.getBean(MyService3.class));
    return root;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...