5

i have come to need to invent a new type of annotations, one of fields of which would be a Spring Expression Language (aka SpEL) expression string.

After a bit googling and examining existing classes, i've figured out that the way of evaluating expression might be like this one (correct me if i am wrong in any way):

    ExpressionParser parser = new SpelExpressionParser();
    Expression exp = parser.parseExpression("isAnonymous()"); // well, this is only an example
    SecurityExpressionRoot context = ... obtaining the instance of subclass of SecurityExpressionRoot ...
    System.out.println(exp.getValue(context)); // just an example

But here is the problem: the most suiting for my case MethodSecurityExpressionRoot is package-local. There is even a task about making it public in Spring Security JIRA which didn't got any attention from developers for a year.

And even if it wasn't package-local, i still have a weak understanding of where to obtain objects for methods setTrustResolver, setRoleHierarchy and setPermissionEvaluator of SecurityExpressionRoot class, which seems to be needed for it's proper functioning.

So, my question is: how do you properly get the correct SecurityExpressionRoot-subclass instance and how to populate it with required objects?

4

2 に答える 2

1

私は同じ問題を解決しています。メニュー項目のリストがあります。各メニュー項目には、セキュリティ表現文字列 (SpEl) が含まれています。@PostFilter("filterObject.securityExpression") を使用しようとしましたが、SpEl 文字列内の SpEl 文字列を評価する方法がわかりませんでした。

だから私はカスタムエバリュエータービーンになりました。org.thymeleaf.extras.springsecurity4.auth.AuthUtils に大きく影響を受けています。

エバリュエーターは、Web セキュリティ フィルターと同じ SecurityExpressionHandler を使用します。これは、評価コンテキストにリクエストとレスポンスを提供する必要があることを意味します。ただし、Spring はこれらの値をコントローラー メソッドに挿入するため、これは複雑ではありません。

評価者:

@Component
public class WebSecurityExpressionEvaluator {

    private static final FilterChain EMPTY_CHAIN = (request, response) -> {
        throw new UnsupportedOperationException();
    };

    private final List<SecurityExpressionHandler> securityExpressionHandlers;

    public WebSecurityExpressionEvaluator(List<SecurityExpressionHandler> securityExpressionHandlers) {
        this.securityExpressionHandlers = securityExpressionHandlers;
    }

    public boolean evaluate(String securityExpression, HttpServletRequest request, HttpServletResponse response) {
        SecurityExpressionHandler handler = getFilterSecurityHandler();

        Expression expression = handler.getExpressionParser().parseExpression(securityExpression);

        EvaluationContext evaluationContext = createEvaluationContext(handler, request, response);

        return ExpressionUtils.evaluateAsBoolean(expression, evaluationContext);
    }

    @SuppressWarnings("unchecked")
    private EvaluationContext createEvaluationContext(SecurityExpressionHandler handler, HttpServletRequest request, HttpServletResponse response) {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        FilterInvocation filterInvocation = new FilterInvocation(request, response, EMPTY_CHAIN);

        return handler.createEvaluationContext(authentication, filterInvocation);
    }

    private SecurityExpressionHandler getFilterSecurityHandler() {
        return securityExpressionHandlers.stream()
                .filter(handler -> FilterInvocation.class.equals(GenericTypeResolver.resolveTypeArgument(handler.getClass(), SecurityExpressionHandler.class)))
                .findAny()
                .orElseThrow(() -> new IllegalStateException("No filter invocation security expression handler has been found! Handlers: " + securityExpressionHandlers.size()));
    }
}

コントローラーメソッドとしての使用法:

@ModelAttribute("adminMenuItems")
public List<AdminMenuItem> getMenuItems(HttpServletRequest request, HttpServletResponse response) {
    List<AdminMenuItem> menuItems = ...
    return menuItems.stream().filter(item -> evaluator.evaluate(item.getSecurityExpression(), request, response)).collect(toList());
}
于 2017-02-23T13:31:32.913 に答える
0

新しい注釈なしでこれを正確に達成することができました。最初に行う必要があるのは、メニュー項目を sec:authorize タグでラップすることです。ここで、sec 名前空間は spring security taglibs からのものです。を使用しております:

<sec:authorize access="hasRole('${menuItem.permission}')"></sec:authorzie>

where${menuItem.permission}permission現在のmenuItemオブジェクトのフィールドです (サーバーから取得した menuItem をループしています)。SpElhasRole()は、Spring によってクラスに実装されorg.springframework.security.access.expression.SecurityExpressionOperationsます。

それはあなたにセキュリティを与えませんが、それはGUIを良くするだけです. サーバーも次のような方法で保護する必要があります。

@PreAuthorize("hasRole('...')")

注釈も春のセキュリティからの@PreAuthorizeものであり、ユーザーが特定の役割を持っていない限り、クライアントがサーバーでメソッドを実行するのを防ぎます。これを機能させるには、 を実装する必要がありましたorg.springframework.security.cas.userdetails.AbstractCasAssertionUserDetailsService。ほとんどの ID 管理サーバーには、同様のクラスが存在します。も実装する必要がありましたorg.jasig.services.persondir.support.ldap.LdapPersonAttributeDaoが、ldap も使用しています。YMMV。

于 2013-06-23T22:28:42.147 に答える