2009-02-04 2 views
2

У меня есть следующая ситуация: механизм авторизации моего приложения реализован с использованием Spring безопасности. Центральный класс реализует AccessDecisionManager и использует избирателей (каждый из которых реализует AccessDecisionVoter), чтобы решить, предоставлять ли доступ к определенному методу или нет. Алгоритм, который подсчитывает голоса является обычай:Как выбросить информативное исключение из AccessDecisionManager, который использует избирателей

public class PermissionManagerImpl extends AbstractAccessDecisionManager { 

    public void decide(
      Authentication authentication, 
      Object object, 
      ConfigAttributeDefinition config) throws AccessDeniedException { 
     Iterator<?> iter = getDecisionVoters().iterator(); 
     boolean wasDenied = false; 

     while (iter.hasNext()) { 
      AccessDecisionVoter voter = (AccessDecisionVoter) iter.next(); 
      int result = voter.vote(authentication, object, config); 

      switch (result) { 
       // Some tallying calculations 
      } 
     } 

     if (wasDenied) { 
      throw new AccessDeniedException("Access is denied"); 
     }    
    } 

} 

После отказывая доступ к каким-либо способом, клиент приложения заинтересован в получении информативное исключение, которое указывает именно почему доступ запрещен. Это подразумевает передачу некоторой информации от избирателей руководителю решения. К сожалению, единственная информация, стандартная AccessDecisionVoter переходит обратно к менеджеру решения является одним из возможных возвращаемых значений (ACCESS_GRANTED, ACCESS_ABSTAIN или ACCESS_DENIED).

Каков наилучший способ сделать это?

Спасибо.

ответ

3

Ну, интерфейс AccesssDecisionVoter фактически возвращает int в этой ситуации. Разумеется, встроенные реализации избирателей всегда возвращают только одну из трех констант, о которых вы упомянули (и это то, что проверяют менеджеры стандартного доступа), но тогда у них действительно нет ничего лишнего, чтобы вернуться - например, RoleVoter запретить доступ, если и только если руководитель не имеет требуемой роли.

Так как вы используете свои собственные реализации как избирателей и управляющего решения доступа, у вас есть несколько вариантов доступны как я это вижу:

  1. Возвращенные другие значения целых чисел как той или иной форме кода ошибки; обрабатывают ACCESS_GRANTED, ACCESS_ABSTAIN и ACCESS_DENIED как их типичные значения, но обрабатывают любое другое целое число как «доступ запрещен» кодом ошибки. В идеале имеется таблица поиска кодов ошибок - по существу, перечисление бедного человека.
  2. В пределах вашего избирателя, возвращайте ACCESS_DENIED, как обычно, и установите какое-либо общедоступное свойство (либо на самом объекте избирателя, либо в каком-то статически доступном поле) с причиной ошибки. В вашем менеджере, если вы получили доступ от своего пользовательского избирателя, проверьте свойство, чтобы получить информацию.
  3. Как указано выше, установите свойство ошибки в пределах избирателя; но убедитесь, что экземпляр Authentication передается в один из ваших собственных подклассов, который обеспечивает хорошее местоположение для установки/получения этой информации.
  4. Бросьте AccessDeniedException (или соответствующий подкласс) из самого вашего избирателя. Это не идеально, поскольку предполагает логику в диспетчере решений доступа; но вы можете либо запустить этот пузырь прямо, либо, если необходимо, поймать его в менеджере (пользовательский подкласс определенно будет хорош для этого) и реконструировать, если доступ действительно отрицается (что-то похожее на то, что класс ProviderManager делает с его переменной lastException) ,

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

1

Не можете ли вы реализовать AccessDecisionManager напрямую, без использования избирателей? Затем вы можете отправить AccessDeniedException с правильной информацией. Возможно, RoleVoter s не являются правильной абстракцией для использования в вашем случае.

2

Спасибо всем, кто ответил.

Я думаю, что нашел довольно элегантный способ сделать то, что хотел, и по-прежнему использовать стандартный API избирателей. Второй параметр для голосов метод AccessDecisionVoter - защищенный объект. Я могу создать контракт между менеджером решений и избирателями, что этот объект имеет определенный класс/интерфейс, который является оберткой , через которую может быть извлечен исходный защищенный объект, а также может быть добавлена ​​дополнительная информация от избирателей, которые запретить доступ.

Я видел такой же шаблон в других рамках. Это решение имеет следующие преимущества по сравнению с другими возможными решениями:

  • избиратели могут остаться без гражданства, так что они могут быть одиночками
  • Стандартный интерфейс AccessDecisionVoter используется и никаких новые возвращаемые значения не будут добавлены
  • дополнительная информация сохраняется в объекте, который отбрасывается автоматически, потому что никто не использует его после AbstactDecisionManager «s решают метод, поэтому никакой код очистки не требуется

Cheers.

Смежные вопросы