[英]How can I enable request only for user's own endpoint
I have a rest-endpoint like this: /users/{userId}/something 我有一个这样的休息端点:/ users / {userId} / something
I implemented authentification using oauth2. 我使用oauth2实现了身份验证。 My WebSecurityConfig looks like this:
我的WebSecurityConfig看起来像这样:
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login").permitAll();
}
How can I only allow users to access their own endpoint (eg. User with Id 100 can only access /users/100/something
) without beeing able to see another endpoint (like /users/200/something
)? 如何仅允许用户访问自己的终结点(例如,ID为100的用户只能访问
/users/100/something
)而无法看到另一个终结点(例如/users/200/something
)?
Is this possible? 这可能吗?
There are many ways to solve this problem, but i have picked out three solutions to apraoch this problem. 有很多方法可以解决此问题,但我已经提出了三种解决该问题的方法。
I would recommend a custom security based annotation approach. 我建议使用基于自定义安全性的注释方法。 This would involve implementing a custom security expression, the related expression handler and the method security configuration.
这将涉及实现自定义安全性表达式,相关的表达式处理程序和方法安全性配置。 The next appraoch is a little bit simpler if this is too much work for you.
如果这对您来说太多了,那么下一个方法会更简单一些。
public class UserIdentityMethodSecurityExpressionRoot
extends SecurityExpressionRoot implements MethodSecurityExpressionOperations {
public UserIdentityMethodSecurityExpressionRoot(Authentication authentication) {
super(authentication);
}
public boolean userIdentity(Long userId) {
User user = ((UserPrincipal) this.getPrincipal()).getUser();
return user.getId() == userId;
}
}
Rest endpoints or service methods can then be annotated with the newly created security expression: 然后,可以使用新创建的安全性表达式对其余端点或服务方法进行注释:
@PreAuthorize("userIdentity(#userId)")
@GetMapping
@ResponseBody
public Resource fineOne(@PathVariable Long userId) {
return resourceService.findOne(id);
}
Please note that the userId
must be provided somewhere , either as @PathVariable
or @RequestParam
. 请注意,必须在某处以
@PathVariable
或@RequestParam
形式提供userId
。 Spring security will then check if the current user has matches the provided userId
and returns 403
otherwise. 然后,Spring Security将检查当前用户是否与提供的
userId
匹配,否则返回403
。
The full example is available here and has been adapted in this question for your purposes. 完整的示例在此处可用,并且已针对您的目的在此问题中进行了调整。
You can also use SpEL, which is a little bit simpler: 您还可以使用SpEL,这有点简单:
@PreAuthorize("#userId == principal.getId()")
@GetMapping
@ResponseBody
public Resource fineOne(@PathVariable Long userId) {
return resourceService.findOne(id);
}
You can also do all the work yourself and get to a faster result without defining a custom expression using SecurityContextHolder
. 您也可以自己完成所有工作,并获得更快的结果,而无需使用
SecurityContextHolder
定义自定义表达式。
public static void checkUserIdentity(Long userId) {
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
// user did not provide a token
if(auth == null) {
throw new AccessDeniedException();
}
UserDetails details = (UserDetails) auth.getPrincipal();
if(userId != details.getId()) {
throw new AccessDeniedException();
}
}
And using it like: 并像这样使用它:
@GetMapping
@ResponseBody
public Resource fineOne(@PathVariable Long userId) {
SecurityUtils.checkUserIdentity(userId)
return resourceService.findOne(id);
}
Why does this work? 为什么这样做? The
SecurityContextHolder
will inject the current principal if you have setup Spring security correctly. 如果您已经正确设置了Spring安全性,那么
SecurityContextHolder
将注入当前的主体。 By default, an authentication is bound to the current thread of execution and will be reset if the request has been processed or encounters an exception. 默认情况下,身份验证绑定到当前的执行线程,如果请求已处理或遇到异常,则将重置身份验证。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.