在Pre / Post-Authorize中获取方法名称

时间:2014-04-22 13:11:11

标签: spring spring-security

我正在为Spring安全编写自己的PermissionEvaluator,而我要做的其中一件事就是弄清楚它正在保护的方法的名称。

例如,如果没有图片中的方法名称,我会有:

postAuthorize("hasPermission(returnObject,'read')")
Event getEvent(int evendId) {
...
}

public boolean hasPermission(Authentication authentication, Object targetDomainObject, Object permission) {
    if(targetDomainObject instanceof Event) {

        return hasPermission(authentication, targetDomainObject, permission);
    }
    return targetDomainObject == null;
}

但我还需要方法名称" getEvent"可以使用hasPermission。我可以通过在hasPermission调用中手动传入它来完成此操作,如下所示:

@PostAuthorize("hasPermission(new com.example.AuthZObject(returnObject,'getEvent'),'read')")
Event getEvent(int eventId);

但是有更多自动化的方法吗?

2 个答案:

答案 0 :(得分:2)

@Ralph在这里非常有正确的想法。第一步是创建MethodSecurityExpressionOperations的自定义实现,该实现可以将Method存储在其上并使用它来计算表达式。例如:

public class MyMethodSecurityExpressionRoot extends SecurityExpressionRoot implements MethodSecurityExpressionOperations {
    private Object filterObject;
    private Object returnObject;
    private Object target;
    private Method method;

    public MyMethodSecurityExpressionRoot(Authentication a) {
        super(a);
    }

    // allow the method to be set    
    public void setMethod(Method m) {
        this.method = m;
    }

    // optionally expose the method to be accessed in expressions    
    public Method getMethod() {
        return method;
    }

    // create a method that will perform the check with 
    // the method name transparently for you    
    public boolean hasMethodPermission(Object target, Object permission) {
        boolean result = false;

        // do your calculations using the method member variable 
        // i.e. method.getName() and the arguments passed in
        // of course you could delegate to another object if you want
        // i.e.
        // return hasPermission(new com.example.AuthZObject(target,method.getName()),permission));
        // or you could do the logic right here

        return result;
    }

    // implement the interface and provide setters

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

    public Object getFilterObject() {
        return filterObject;
    }

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

    public Object getReturnObject() {
        return returnObject;
    }

    public void setThis(Object target) {
        this.target = target;
    }

    public Object getThis() {
        return target;
    }
}

接下来扩展DefaultMethodSecurityExpressionHandler并使用自定义表达式root。

public class MySecurityExpressionHandler extends DefaultMethodSecurityExpressionHandler{

    @Override
    protected MethodSecurityExpressionOperations createSecurityExpressionRoot(Authentication authentication, MethodInvocation invocation){
        MyMethodSecurityExpressionRoot root = new MyMethodSecurityExpressionRoot(authentication);
        root.setThis(invocation.getThis());
        root.setPermissionEvaluator(getPermissionEvaluator());
        root.setTrustResolver(new AuthenticationTrustResolverImpl());
        root.setRoleHierarchy(getRoleHierarchy());
        root.setMethod(invocation.getMethod());
        return root;
    }
}

配置MySecurityExpressionHandler后,您应该能够使用以下内容:

@PostAuthorize("hasMethodPermission(returnObject,'read')")
Event getEvent(int eventId);

答案 1 :(得分:1)

我不知道这是否可行,但你应该看一下DefaultMethodSecurityExpressionHandler。这个类有两种方法:

public final EvaluationContext createEvaluationContext(Authentication authentication, T invocation) {
    SecurityExpressionOperations root = createSecurityExpressionRoot(authentication, invocation);
    StandardEvaluationContext ctx = createEvaluationContextInternal(authentication, invocation);
    ctx.setBeanResolver(br);
    ctx.setRootObject(root);

    return ctx;
}

protected MethodSecurityExpressionOperations createSecurityExpressionRoot(Authentication authentication, MethodInvocation invocation) {
    MethodSecurityExpressionRoot root = new MethodSecurityExpressionRoot(authentication);
    root.setThis(invocation.getThis());
    root.setPermissionEvaluator(getPermissionEvaluator());
    root.setTrustResolver(trustResolver);
    root.setRoleHierarchy(getRoleHierarchy());

    return root;
}

我觉得您需要使用所需的其他字段扩展类MethodSecurityExpressionOperations,然后您需要继承DefaultMethodSecurityExpressionHandler并替换createSecurityExpressionRoot方法以便它返回您的扩展MethodSecurityExpressionOperations填充了字段。

然后,您可以向扩展的MethodSecurityExpressionOperations添加能够访问此附加字段的新方法。