无法评估带有字符串列表的 SpEL 表达式

SpEL expression with String list fails to be evaluated

10 月 27 日更新

以下方法具有基于 SpEL 的 ACL 注释。意思是检查fileId的文件对象是否有ReadWrite的权限。如果文件对象包含这两个权限中的任何一个,ACL通过,否则抛出异常。

@Component
public class ApiImpl {
    @PreAuthorize("@acl.hasPermissions('File',{'Read','Write'}, #fileId)")
    public FileListVO getFiles(String fileId) {
        ...
    }
}

注释通过下面的acl组件。

public interface AclService {
    boolean hasPermissions(String type, List<String> permissions, Object resource, Object... resourceContext);
}

@Component("acl")
public class AclServiceImpl implements AclService {

    @Override
    public boolean hasPermissions(String type, List<String> permissions, Object resource, Object... resourceContext) {
        List<String> resourcePermissions = get permissions of resource
        if (resourcePermissions contains any of permissions) {
            return true;
        }
        throw exception here
    }
}

问题是,下面的 SpEL 表达式无法计算:

@PreAuthorize("@acl.hasPermissions('File',{'Read','Write'}, #fileId)")
java.lang.IllegalArgumentException: Failed to evaluate expression '@acl.hasPermissions('File',{'Read','Write'}, #fileId)'
There is a List<String> permissions in it. What is the correct expression for this?

请注意 AclServiceImpl.hasPermissions() 中的 throw exception 行为是遗留代码,我不想更改。 @PreAuthorize("@acl.hasPermissions('File',{'Read','Write'}, #fileId)") 预计 return true 不会抛出异常。我知道以下可能是一个选项,

public interface AclService {
    boolean hasPermission(String type, String permission, Object resource, Object... resourceContext);
}

@Component("acl")
public class AclServiceImpl implements AclService {

    @Override
    public boolean hasPermission(String type, String permission, Object resource, Object... resourceContext) {
        List<String> resourcePermissions = get permissions of resource
        if (resourcePermissions contains permission) {
            return true;
        }
        return false; // not throw exception
    }
}

@Component
public class ApiImpl {
    @PreAuthorize("@acl.hasPermissions('File','Read', #fileId)"
        + "|| @acl.hasPermissions('File','Write', #fileId)")
    @PostMeetingTelemetry()
    public FileListVO getFiles(String fileId) {
        ...
    }
}

但我只是想知道如何增强

@PreAuthorize("@acl.hasPermissions('File',{'Read','Write'}, #fileId)")

这样下面的代码就可以工作了。

public interface AclService {
    boolean hasPermissions(String type, List<String> permissions, Object resource, Object... resourceContext);
}

@Component("acl")
public class AclServiceImpl implements AclService {

    @Override
    public boolean hasPermissions(String type, List<String> permissions, Object resource, Object... resourceContext) {
        List<String> resourcePermissions = get permissions of resource
        if (resourcePermissions contains any of permissions) {
            return true;
        }
        throw exception here
    }
}

@Component
public class ApiImpl {
    @PreAuthorize("@acl.hasPermissions('File',{'Read','Write'}, #fileId)")
    public FileListVO getFiles(String fileId) {
        ...
    }
}

throw exception here

当然,如果你在那里抛出异常,评估就会失败。

您应该 return false。

通过以下更改,它可以工作。不确定是否需要第 1 个更改,但第 2 个更改是必须的。

  1. List<String> 替换为 String[] 以获得 permissions
  2. {'Read','Write'}替换为new String[]{'Read','Write'}

之前

public interface AclService {
    boolean hasPermissions(String type, List<String> permissions, Object resource, Object... resourceContext);
}

@Component("acl")
public class AclServiceImpl implements AclService {

    @Override
    public boolean hasPermissions(String type, List<String> permissions, Object resource, Object... resourceContext) {
        List<String> resourcePermissions = get permissions of resource
        if (resourcePermissions contains any of permissions) {
            return true;
        }
        throw exception here
    }
}

@Component
public class ApiImpl {
    @PreAuthorize("@acl.hasPermissions('File',{'Read','Write'}, #fileId)")
    @PostMeetingTelemetry()
    public FileListVO getFiles(String fileId) {
        ...
    }
}

之后

public interface AclService {
    // Replace List<String> with String[]
    boolean hasPermissions(String type, String[] permissions, Object resource, Object... resourceContext);
}

@Component("acl")
public class AclServiceImpl implements AclService {

    @Override
    public boolean hasPermissions(String type, String[] permissions, Object resource, Object... resourceContext) {
        List<String> resourcePermissions = get permissions of resource
        if (resourcePermissions contains any of permissions) {
            return true;
        }
        throw exception here
    }
}

@Component
public class ApiImpl {
    // Replace {'Read','Write'} with new String[]{'Read','Write'}
    @PreAuthorize("@acl.hasPermissions('File',new String[]{'Read','Write'}, #fileId)")
    @PostMeetingTelemetry()
    public FileListVO getFiles(String fileId) {
        ...
    }
}