Создание пользовательских методов для использования в аннотациях языка выражений безопасности spring


Я хотел бы создать класс, который добавляет пользовательские методы для использования в языке выражений безопасности spring для авторизации на основе методов с помощью аннотаций.

например, я хотел бы создать пользовательский метод, такой как "customMethodReturningBoolean", который будет использоваться как-то так:

  @PreAuthorize("customMethodReturningBoolean()")
  public void myMethodToSecure() { 
    // whatever
  }

мой вопрос таков. Если это возможно, какой класс я должен подкласс для создания моих пользовательских методов, как бы я мог настроить его в файлах конфигурации spring xml и кто-нибудь даст мне пример пользовательского метода, используемого таким образом?

3 80

3 ответа:

вам нужно будет подкласс два класса.

во-первых, установить новый метод обработчика выражение

<global-method-security>
  <expression-handler ref="myMethodSecurityExpressionHandler"/>
</global-method-security>

myMethodSecurityExpressionHandler будет подклассом DefaultMethodSecurityExpressionHandler, который переопределяет createEvaluationContext(), установка подкласса MethodSecurityExpressionRoot на MethodSecurityEvaluationContext.

например:

@Override
public EvaluationContext createEvaluationContext(Authentication auth, MethodInvocation mi) {
    MethodSecurityEvaluationContext ctx = new MethodSecurityEvaluationContext(auth, mi, parameterNameDiscoverer);
    MethodSecurityExpressionRoot root = new MyMethodSecurityExpressionRoot(auth);
    root.setTrustResolver(trustResolver);
    root.setPermissionEvaluator(permissionEvaluator);
    root.setRoleHierarchy(roleHierarchy);
    ctx.setRootObject(root);

    return ctx;
}

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

EDIT 11/19/14 Setup Spring для использования аннотаций безопасности:

<beans ... xmlns:sec="http://www.springframework.org/schema/security" ... >
...
<sec:global-method-security pre-post-annotations="enabled" />

создать боб, как это:

@Component("mySecurityService")
public class MySecurityService {
    public boolean hasPermission(String key) {
        return true;
    }
}

тогда сделайте что-то вроде этого в вашем jsp:

<sec:authorize access="@mySecurityService.hasPermission('special')">
    <input type="button" value="Special Button" />
</sec:authorize>

или аннотировать метод:

@PreAuthorize("@mySecurityService.hasPermission('special')")
public void doSpecialStuff() { ... }

и помните: если вы используете весну и вы должны решить проблему путем расширения классов, переопределение методов, реализации интерфейсов и т. д... тогда вы, вероятно, делаете что-то неправильно. Это все аннотации и xml, поэтому мы так любим Spring, а не (старые версии) EJB.

кроме того, вы можете использовать Язык Весеннего Выражения в своем @PreAuthorize аннотации для доступа к текущей аутентификации, а также аргументов метода.

например:

@Component("mySecurityService")
public class MySecurityService {
    public boolean hasPermission(Authentication authentication, String foo) { ... }
}

затем обновите @PreAuthorize чтобы соответствовать новой сигнатуре метода:

@PreAuthorize("@mySecurityService.hasPermission(authentication, #foo)")
public void doSpecialStuff(String foo) { ... }

спасибо ericacm, но он не работает по нескольким причинам:

  • свойства DefaultMethodSecurityExpressionHandler являются частными (отражение видимость kludges нежелательно)
  • по крайней мере, в моем затмении, я не могу решить MethodSecurityEvaluationContext объект

разница в том, что мы называем существующим createEvaluationContext метод и после этого добавляет нашу таможню корневой объект. Наконец я только что вернулся StandardEvaluationContext тип объекта, так как MethodSecurityEvaluationContext не будет разрешаться в компиляторе (они оба из одного интерфейса). Это код, который я сейчас имею в производстве.

сделать MethodSecurityExpressionHandler использовать наш пользовательский корень:

public class CustomMethodSecurityExpressionHandler extends DefaultMethodSecurityExpressionHandler  {

    // parent constructor
    public CustomMethodSecurityExpressionHandler() {
        super();
    }

    /**
     * Custom override to use {@link CustomSecurityExpressionRoot}
     * 
     * Uses a {@link MethodSecurityEvaluationContext} as the <tt>EvaluationContext</tt> implementation and
     * configures it with a {@link MethodSecurityExpressionRoot} instance as the expression root object.
     */
    @Override
    public EvaluationContext createEvaluationContext(Authentication auth, MethodInvocation mi) {
        // due to private methods, call original method, then override it's root with ours
        StandardEvaluationContext ctx = (StandardEvaluationContext) super.createEvaluationContext(auth, mi);
        ctx.setRootObject( new CustomSecurityExpressionRoot(auth) );
        return ctx;
    }
}

это заменяет корень по умолчанию путем расширения SecurityExpressionRoot. Здесь я переименовал hasRole to hasEntitlement:

public class CustomSecurityExpressionRoot extends SecurityExpressionRoot  {

    // parent constructor
    public CustomSecurityExpressionRoot(Authentication a) {
        super(a);
    }

    /**
     * Pass through to hasRole preserving Entitlement method naming convention
     * @param expression
     * @return boolean
     */
    public boolean hasEntitlement(String expression) {
        return hasRole(expression);
    }

}

наконец обновить securityContext.xml (и убедитесь, что на него ссылаются из вашего applcationContext.xml):

<!-- setup method level security using annotations -->
<security:global-method-security
        jsr250-annotations="disabled"
        secured-annotations="disabled"
        pre-post-annotations="enabled">
    <security:expression-handler ref="expressionHandler"/>
</security:global-method-security>

<!--<bean id="expressionHandler" class="org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler">-->
<bean id="expressionHandler" class="com.yourSite.security.CustomMethodSecurityExpressionHandler" />

Примечание: аннотация @Secured не примет это переопределение, поскольку оно выполняется через другой обработчик проверки. Итак, в приведенном выше xml я отключил их, чтобы предотвратить последующую путаницу.