【问题标题】:Using @RolesAllowed to filter entity properties with RESTEasy and Jackson使用 @RolesAllowed 通过 RESTEasy 和 Jackson 过滤实体属性
【发布时间】:2017-06-13 12:45:27
【问题描述】:

使用 RESTEasy 和 Jackson,是否可以在我的模型中使用 @RolesAllowed 注释,以避免某些属性在输出中被序列化,具体取决于用户的角色?

我已经找到了大量关于如何使用 Jersey 执行此操作的文档,但没有找到 RESTEasy。

我在这个架构上被阻止了,所以切换库不是一个选项,并且使用自定义 ObjectMapper 解释 here 也不是一个选项,因为模型足够大,以至于它太耗时了标记大型数据集的每个属性以进行正确的序列化。另外,这是指较旧版本的 Jackson 库,我不确定如何使其与新版本一起使用。

编辑

具体请参阅this blog post 以了解我要完成的工作。请注意,这是特定于泽西岛的,到目前为止,我没有找到有关 RESTEasy 的文档来完成此操作。

【问题讨论】:

  • 指出的解决方案应该适用于最新版本的 Jackson 和 RESTEasy。您提到:模型足够大,以至于标记大型数据集的每个属性以进行正确序列化非常耗时好的,那么您将应用哪些标准来过滤属性?
  • 解决方案参考了ObjectMapper::getSerializationConfig::setSerializationView这个方法,这个方法早就被弃用了。我尝试了withView 方法,它看起来相同但没有结果。如问题中所述,标准是用户必须具有访问该字段的特定权限。例如。具有管理员权限的用户将能够访问它,否则不能。恕我直言,它也使代码更易于阅读和区分用例。
  • 我了解您想要执行特定于角色的序列化。我要问的是:如果您不想使用视图(注释每个 bean 的每个属性),您将使用哪些标准来选择将被序列化的属性?我想到的一个选项是按名称过滤属性(例如,使用SimpleBeanPropertyFilter)。然后,在ContextResolver 中,您将设置过滤器,而不是设置视图。
  • 我明白你的意思,我正在寻找一种使 @RolesAllowed 注释工作的方法:这样可以使用正确的角色和 EJB 容器对 getProperty() 方法进行注释将不允许调用该方法,从而删除该属性,如此处所述 blog.dejavu.sk/2014/02/04/… (请注意,这适用于 Jersey,而不是 RESTEasy)。我正在寻找等效的解决方案。我希望我已经更清楚了,很抱歉造成误解
  • 我只是在实施它,准确无误,谢谢 :)

标签: java jackson resteasy


【解决方案1】:

如果您不愿意使用@JsonView,可以考虑使用@JsonFilter。首先需要扩展SimpleBeanPropertyFilter,并根据用户角色控制序列化:

public class RoleBasedPropertyFilter extends SimpleBeanPropertyFilter {

    private String allowedRole;

    public RoleBasedPropertyFilter(String allowedRole) {
        this.allowedRole = allowedRole;
    }

    @Override
    public void serializeAsField(Object pojo, JsonGenerator jgen,
                                 SerializerProvider provider, 
                                 PropertyWriter writer) throws Exception {

        PermitAll permitAll = writer.getAnnotation(PermitAll.class);
        if (permitAll != null) {
            serializeAsField(pojo, jgen, provider, writer);
            return;
        }

        DenyAll denyAll = writer.getAnnotation(DenyAll.class);
        if (denyAll != null) {
            writer.serializeAsOmittedField(pojo, jgen, provider);
            return;
        }

        RolesAllowed rolesAllowed = writer.getAnnotation(RolesAllowed.class);
        if (rolesAllowed != null) {
            if (!Arrays.asList(rolesAllowed.value()).contains(allowedRole)) {
                writer.serializeAsOmittedField(pojo, jgen, provider);
                return;
            }
        }

        // If no annotation is provided, the property will be serialized
        writer.serializeAsField(pojo, jgen, provider);
    }
}

要将过滤器应用于某个 bean,请使用 @JsonFilter("roleBasedPropertyFilter") 对其进行注释:

@JsonFilter("roleBasedPropertyFilter")
public class User {

    private String firstName;
    private String lastName;
    private String email;
    private String password;

    public String getFirstName() {
        return firstName;
    }

    public String getLastName() {
        return lastName;
    }

    @RolesAllowed({"ADMIN"})
    public String getEmail() {
        return email;
    }

    @DenyAll
    public String getPassword() {
        return password;
    }

    // Other getters and setters
}

然后在ContextResolver 中为ObjectMapper 注册您的过滤器:

String currentUserRole = // Get role from the current user

FilterProvider filterProvider = new SimpleFilterProvider()
        .addFilter("roleBasedPropertyFilter", 
                new RoleBasedPropertyFilter(currentUserRole));

ObjectMapper mapper = new ObjectMapper();
mapper.setFilterProvider(filterProvider);

如果你想让你的过滤器“全局”,即应用于所有bean,你可以创建一个混合类并用@JsonFilter("roleBasedPropertyFilter")注释它:

@JsonFilter("roleBasedPropertyFilter")
public class RoleBasedPropertyFilterMixIn {

}

然后将mix-in类绑定到Object

mapper.addMixIn(Object.class, RoleBasedPropertyFilterMixIn.class);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-20
    • 1970-01-01
    • 2015-08-04
    • 1970-01-01
    • 1970-01-01
    • 2012-02-24
    相关资源
    最近更新 更多