如何允许用户在 Spring Boot / Spring Security 中仅访问自己的数据?
Posted
技术标签:
【中文标题】如何允许用户在 Spring Boot / Spring Security 中仅访问自己的数据?【英文标题】:How to allow a User only access their own data in Spring Boot / Spring Security? 【发布时间】:2019-01-13 17:08:20 【问题描述】:我有一些这样的 api:
/users/user_id
/users/user_id/orders
/users/user_id/orders/order_id
我必须如何保护它们?每个用户只能看到她/他的数据,但管理员可以看到所有数据。
我必须如何在 Spring Security 中实现 Id == 1 的用户无法看到 Id == 2 的用户数据,反之亦然,期望管理员角色的用户可以看到所有内容?
我是否在会话中的每个方法用户 ID 与传递给 api 的 user_id 参数相等之前检查?有没有更好的办法?
p.s:我使用 Spring Security 的 JWT。
【问题讨论】:
【参考方案1】:在任何@Controller
、@RestController
注释的bean 中,您都可以直接使用Principal
作为方法参数。
@RequestMapping("/users/user_id")
public String getUserInfo(@PathVariable("user_id") Long userId, Principal principal)
// test if userId is current principal or principal is an ADMIN
....
如果您不想在 Controller
s 中进行安全检查,您可以使用 Spring EL 表达式。
您可能已经使用了一些内置表达式,例如 hasRole([role])
。
你可以自己写表达式。
-
创建
bean
@Component("userSecurity")
public class UserSecurity
public boolean hasUserId(Authentication authentication, Long userId)
// do your check(s) here
-
用你的表达方式
http
.authorizeRequests()
.antMatchers("/user/userId/**")
.access("@userSecurity.hasUserId(authentication,#userId)")
...
好消息是您还可以组合以下表达式:
hasRole('admin') or @userSecurity.hasUserId(authentication,#userId)
【讨论】:
我可以用 AOP 做吗? 如果您在使用自定义表达式时遇到问题,请在“public class UserSecurity”行上方添加“@Component("userSecurity")” 但是“在任何 @Controller、@RestController 注释的 bean 中,您都可以直接使用 Principal 作为方法参数。”不管用。校长只是null
@ACV 是的.... 主体应该可以访问参考:principal-in-restcontroller
@ACV 这里是一个很好的概述spring.io guide: spring-security-architecture,你应该看看Web Security
部分【参考方案2】:
您也可以在服务接口上使用@PreAuthorize。如果您有自定义 userdetails 对象,那么您可以轻松完成。 在我的一个项目中,我是这样做的:
@PreAuthorize(value = "hasAuthority('ADMIN')"
+ "or authentication.principal.equals(#post.member) ")
void deletePost(Post post);
顺便说一句,这是在服务接口中。您必须确保添加正确的注释才能使预授权生效。
【讨论】:
【参考方案3】:您应该首先选择您的安全策略, 您需要的名称为“Row Filtering”,这是3A(Authentication,Authorization,Audit)概念的授权概念之一。
如果您想实施综合解决方案,请查看:
https://docs.spring.io/spring-security/site/docs/3.0.x/reference/domain-acls.html
Spring ACL 完全涵盖了诸如“行过滤”、“白黑名单”、“角色基础授权”、“ACL 继承”、“角色投票者”等概念。
否则,您应该为每个要保护的业务案例保存所有者,并在您的服务层中过滤它们。
【讨论】:
【参考方案4】:我们可以创建一个像@IsUser
这样的注解并将其与控制器方法一起使用。
例子:
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@PreAuthorize(value = "hasRole('ROLE_USER')" + "and authentication.principal.equals(#userId) ")
public @interface IsUser
【讨论】:
应该是authentication.principal.username.equals(#userId)
以上是关于如何允许用户在 Spring Boot / Spring Security 中仅访问自己的数据?的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Spring-Boot-REST 调用中获取用户信息?
允许用户使用 jwt 在 Spring Boot 中选择资源
Spring Boot使用JavaMailSender发送邮件