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 many
与 Roles
和 Books
的关系
我正在构建一个应用程序,用于在网站上显示来自数据库的信息。该应用程序使用 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 many
与 Roles
和 Books