Spring应用的服务层如何授权?

How to authorize the service layer of a Spring application?

我正在构建一个应用程序,用于在网站上显示来自数据库的信息。该应用程序使用 Spring 安全性进行保护,我的用户可以具有不同的角色。应根据当前用户的角色显示记录。例如,我想显示数据库中的书籍。角色 X 只能看一些书,角色 Y 也只能看。但是角色ADMIN可以看到所有的书。

现在我想知道授权发生在何处以及如何发生。我以为服务层会是一个好地方,但是我如何查询当前用户角色可以访问的书籍。

我的表格是这样的:

book (id, name)
role (id, name)
role_book (id, role_id, book_id)

因此,对书籍的查询将是 SELECT b.id, b.name FROM book b, role r role_book rb WHERE b.id = rb.book_id AND r.id = rb.role_id AND r.name IN (<roles of the current user>)。当当前用户具有 ADMIN 角色时,我会简单地 select 数据库中的所有书籍。

但是如何在 Spring 服务方法中执行这些查询?我认为这是一个常见的授权任务。是否有任何 Spring 机制可以做到这一点?

对于方法授权,您可以使用 @PreAuthorize("hasRole('ROLE_USER')")

方法之上的注释,这里是关于该主题的 link: http://docs.spring.io/spring-security/site/docs/3.0.x/reference/el-access.html

要检查用户的角色,您还可以使用

SecurityContextHolderAwareRequestWrapper.isUserInRole(String role)

在 Spring 安全 3.0

Spring Security 4 现在有 Spring 数据集成:http://docs.spring.io/spring-security/site/docs/current-SNAPSHOT/reference/htmlsingle/#data

在您的 Spring 数据存储库中:

@Repository
public interface FooRepository extends PagingAndSortingRepository<Foo,Long> {
    @Query("select f from Foo f where f.owner.id = ?#{ principal?.id }")
    Page<Foo> find(Pageable pageable);
}

我会做一个简单的重新设计,这也将使数据层更可重用。应该是这样的。

服务层

这里我们获取当前用户的角色并传递给数据层。

Iterable<Book> findAllMyBooks(){
...
    List<String> roles = new ArrayList<>();
    Authentication authentication = SecurityContextHolder.getContext()getAuthentication();
    for (GrantedAuthority auth : authentication.getAuthorities()) {
        roles.add(auth.getAuthority());
    }
    bookRepository.findAllByRoles(roles);
...
}

数据层

根据角色查询书籍。因此,您稍后可以在管理面板中使用它为未登录用户获取书籍。

请注意,我没有时间检查 JPQL 查询。 'ADMIN' IN (:roles) 中可能存在错误。请检查这个。

@Query("SELECT b FROM Book b INNER JOIN b.roles r WHERE r.name IN (:roles) OR 'ADMIN' IN (:roles)")
Iterable<Book> findAllByRoles(@Param("roles") List<String> roles);

实体模型

映射 Many to manyRolesBooks

的关系