Jackson Json serialization: exclude property respe

2019-03-03 14:44发布

问题:

Is there any way to dynamically exclude a bean property from being serialized if the logged user has not the permissions to see a specific field?

For example, if a bean has fields A,B,C may be that, in the REST response, the admin can see fields A,B,C while a simple user can see only fields A,B. How could I annotate the getter of field C? Can I integrate such annotation with the SecurityContext of Jersey?

I am using Jersey 2.1 and Jackson.

Thanks

回答1:

One possible approach would be to use @JsonView (see also JacksonJsonViews).

Views:

// View definitions:
class Views {
    static class User { }
    static class Admin extends User { }
}

Bean:

public class Bean {

    @JsonView(Views.User.class)
    private A a;
    @JsonView(Views.User.class)
    private B b;

    @JsonView(Views.Admin.class)
    private C c;
}

You would need to create a ContextResolver as described in Jackson section in the user guide. You can inject SecurityContext to this ContextResolver from which you can find out what role is a user in. Your ContextResolver may look like:

@Provider
public class MyObjectMapperProvider implements ContextResolver<ObjectMapper> {

    @Context
    private SecurityContext securityContext;

    @Override
    public ObjectMapper getContext(Class<?> type) {
        final ObjectMapper objectMapper = new ObjectMapper();            

        if (securityContext.isUserInRole("admin")) {
            objectMapper.getSerializationConfig().setSerializationView(Views.Admin.class);
        } else {
            objectMapper.getSerializationConfig().setSerializationView(Views.User.class);
        }

        return objectMapper;
    }
}

EDIT 1:

There is a RFE filed for a similar (more user friendly) use case already (see JERSEY-2013).



回答2:

If you use the same JAX-RS resources for requests with different user roles, you should consider the following solution:

@Provider
public class SecuritySerializerFilter extends JacksonJaxbJsonProvider {
    @Context
    SecurityContext securityContext;

    @Override
    public void writeTo(Object value, Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType, MultivaluedMap<String,Object> httpHeaders, OutputStream entityStream) throws IOException, WebApplicationException {

        ObjectMapper current = locateMapper(type, mediaType);
        setMapper(current.setSerializationConfig(
            current.getSerializationConfig().withView(
                securityContext.isUserInRole("admin") ? Views.Admin.class : Views.User.class
            )
        ));

        super.writeTo(value, type, genericType, annotations, mediaType, httpHeaders, entityStream);
    }
}