Repository access control in Spring Data Rest based off user princpal

跟風遠走 提交于 2019-12-18 10:46:16

问题


I'm attempting to implement fine grain access control while still taking advantage of Spring data rest.

I'm working on securing a CrudRepository so users can only modify or insert data that belongs to them. I'm making use of @PreAuthorize/@PostAuthorize and @PreFilter/@PostFilter to lock access down to the current principal.

So far my repository looks like this.

public interface MyRepository extends CrudRepository<MyObject, Integer> {

    @PreAuthorize("#entity.userId == principal.id")
    @Override
    <S extends MyObject> S save(S entity);

    @PreFilter("filterObject.userId === principal.id")
    @Override
    <S extends MyObject> Iterable<S> save(Iterable<S> entities);

    @PostAuthorize("returnObject.userId == principal.id")
    @Override
    MyObject findOne(Integer integer);

    @PostFilter("filterObject.userId == principal.id")
    @Override
    Iterable<MyObject> findAll();

}

While this is a bit tedious, it does seem to accomplish what I'm after. (If anyone knows a better way, feel free to let me know!)

Where I'm running into problems is with delete(), count() and exists()

    @Override
    long count();

    @Override
    void delete(Integer integer);

    @Override
    void delete(MyObject entity);

    @Override
    void deleteAll();

    @Override
    boolean exists(Integer integer);

These methods either take an Integer ID parameter or none at all. It seems like I would have to first select the entity with the input ID and then perform the auth check.

Is this type of authorization possible within the repository?

Thanks

Edit:

Thanks to ksokol this seems to be working now.

I added a new bean to a @Configuration class

@Bean
public EvaluationContextExtension securityExtension() {
    return new SecurityEvaluationContextExtensionImpl();
}

This bean extends EvaluationContextExtensionSupport and overrides getRootObject to return a SecurityExpressionRoot that holds my custom principal.

public class SecurityEvaluationContextExtensionImpl extends EvaluationContextExtensionSupport {
@Override
public String getExtensionId() {
    return "security";
}

@Override
public Object getRootObject() {
        Authentication authentication =   SecurityContextHolder.getContext().getAuthentication();
        return new SecurityExpressionRoot(authentication){};
    }
}

回答1:


As of Spring Security 4.0 you can access security context in Spring Data JPA queries.

Add SecurityEvaluationContextExtension bean to your bean context:

@Bean
public SecurityEvaluationContextExtension securityEvaluationContextExtension() {
    return new SecurityEvaluationContextExtension();
}

Now you should be able to access Principal in your Spring Data queries:

@Query("select count(m) from MyObject as m where m.user.id = ?#{ principal?.id }")
@Override
long count();

@Modifying
@Query("delete from MyObject as m where m.id = ?1 and m.user.id = ?#{ principal?.id }")
@Override
void delete(Integer integer);

@Modifying
@Query("delete from MyObject as m where m.id = ?1 and m.user.id = ?#{ principal?.id }")
@Override
void delete(MyObject entity);

@Modifying
@Query("delete from MyObject as m where m.user.id = ?#{ principal?.id }")
@Override
void deleteAll();

@Query("select 1 from MyObject as m where m.id = ?1 and m.user.id = ?#{ principal?.id }")
@Override
boolean exists(Integer integer);

Caution. Queries might have errors. I hadn't the time to test it.




回答2:


Can also be achieved by implementing your checks in your custom Spring repository event handlers. See @HandleBeforeCreate, @HandleBeforeUpdate, @HandleBeforeDelete.

Alternatively, you can use permission-based expressions, e.g. with ACL or your custom ones, you can write @PreAuthorize("hasPermission(#id, 'MyObject', 'DELETE')").



来源:https://stackoverflow.com/questions/29688195/repository-access-control-in-spring-data-rest-based-off-user-princpal

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!