Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring Data Rest: Security based projection

Tags:

I am using the current version of Spring Data Rest and Spring Data JPA and have following entity:

public class User {
    @Id
    @GeneratedValue
    private Long id;
    private String name;
    private String password;
    private String email;
   ...getter/setter methods...
}

I am also using Spring Security.

My User Repository:

   @RepositoryRestResource(
     collectionResourceRel = "user", 
     path = "user", 
    excerptProjection = UserSimpleProjection.class)
public interface UserRepository extends PagingAndSortingRepository<User, Long> {

}

For Example:

  • User 1 is logged in
  • User 1 requests http://localhost:8080/user/1 - all fields are visible
  • User 1 requests http://localhost:8080/user/2 - just id and name are visible.

I tried different solutions with Jackson, none of them solved my problem:

  • Use of JsonView: I found no way, to change the view for the ObjectMapper depending on the logged in User
  • Implemented different Jackson Filters as described here with the same issue that I found no way to change the ObjectMapper config for the different requests.

Then I found Projections.

I created a projection:

@Projection(name = "simple", types = User.class)
public interface UserSimpleProjection {

    public Long getId();

    public String getName();
}

and another detailed one:

@Projection(name = "detailed", types = User.class)
public interface UserDetailProjection extends UserSimpleProjection{

    public String getEmail();
}

So far so good, I get different results depending on my request.

Is there a way to automatically switch the projection depending on Spring Security and/or limit different Projections for different roles?

like image 487
Plechi Avatar asked Mar 01 '15 13:03

Plechi


1 Answers

You can add a "virtual" value property into the projection that invoke a service method with security checks:

@Projection(name = "detailed", types = User.class)
public interface UserDetailProjection extends UserSimpleProjection{

    @Value("#{@userService.checkAccess(target)? target.email : null}")
    public String getEmail();
}

Where your custom UserService component would return true if email should be exposed or simply has @PreAuthorize on checkAccess(..) to throw an AccessDeniedException whatever is better for you.

Note, the target property in the SpEL holds the original object - provided by Spring-DATA.

like image 153
aux Avatar answered Dec 21 '22 20:12

aux