Создание пользовательских методов для использования в аннотациях языка выражений безопасности spring
Я хотел бы создать класс, который добавляет пользовательские методы для использования в языке выражений безопасности spring для авторизации на основе методов с помощью аннотаций.
например, я хотел бы создать пользовательский метод, такой как "customMethodReturningBoolean", который будет использоваться как-то так:
@PreAuthorize("customMethodReturningBoolean()")
public void myMethodToSecure() {
// whatever
}
мой вопрос таков. Если это возможно, какой класс я должен подкласс для создания моих пользовательских методов, как бы я мог настроить его в файлах конфигурации spring xml и кто-нибудь даст мне пример пользовательского метода, используемого таким образом?
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 я отключил их, чтобы предотвратить последующую путаницу.