Is there any good way to filter JSON output based on Spring Security roles? I'm looking for something like @JsonIgnore, but for role, like @HasRole("ROLE_ADMIN"). How should I implement this?
Spring security provides few options to register the custom filter. We can use one of them based on our requirement. addFilterAfter(filter, class)–Adds a filter after the position of the specified filter class. addFilterBefore(filter, class)–Filter before the position of the specified filter class.
Spring Security's web infrastructure is based entirely on standard servlet filters. It doesn't use servlets or any other servlet-based frameworks (such as Spring MVC) internally, so it has no strong links to any particular web technology.
Class AuthenticationFilterA Filter that performs authentication of a particular request. An outline of the logic: A request comes in and if it does not match setRequestMatcher(RequestMatcher) , then this filter does nothing and the FilterChain is continued.
For those landing here from Google, here is a similar solution with Spring Boot 1.4.
Define interfaces for each of your roles, e.g.
public class View {
public interface Anonymous {}
public interface Guest extends Anonymous {}
public interface Organizer extends Guest {}
public interface BusinessAdmin extends Organizer {}
public interface TechnicalAdmin extends BusinessAdmin {}
}
Declare @JsonView
in your entities, e.g.
@Entity
public class SomeEntity {
@JsonView(View.Anonymous.class)
String anonymousField;
@JsonView(View.BusinessAdmin.class)
String adminField;
}
And define a @ControllerAdvice
to pick up the right JsonView
based on the roles:
@ControllerAdvice
public class JsonViewConfiguration extends AbstractMappingJacksonResponseBodyAdvice {
@Override
public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
return super.supports(returnType, converterType);
}
@Override
protected void beforeBodyWriteInternal(MappingJacksonValue bodyContainer, MediaType contentType,
MethodParameter returnType, ServerHttpRequest request, ServerHttpResponse response) {
Class<?> viewClass = View.Anonymous.class;
if (SecurityContextHolder.getContext().getAuthentication() != null && SecurityContextHolder.getContext().getAuthentication().getAuthorities() != null) {
Collection<? extends GrantedAuthority> authorities = SecurityContextHolder.getContext().getAuthentication().getAuthorities();
if (authorities.stream().anyMatch(o -> o.getAuthority().equals(Role.GUEST.getValue()))) {
viewClass = View.Guest.class;
}
if (authorities.stream().anyMatch(o -> o.getAuthority().equals(Role.ORGANIZER.getValue()))) {
viewClass = View.Organizer.class;
}
if (authorities.stream().anyMatch(o -> o.getAuthority().equals(Role.BUSINESS_ADMIN.getValue()))) {
viewClass = View.BusinessAdmin.class;
}
if (authorities.stream().anyMatch(o -> o.getAuthority().equals(Role.TECHNICAL_ADMIN.getValue()))) {
viewClass = View.TechnicalAdmin.class;
}
}
bodyContainer.setSerializationView(viewClass);
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With