简体   繁体   English

如何仅对用户自己的端点启用请求

[英]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. 有很多方法可以解决此问题,但我已经提出了三种解决该问题的方法。

Custom Security Expression 自定义安全性表达

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. 完整的示例在此处可用并且已针对您的目的在此问题中进行了调整。

SpEL 规划环境地政司

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);
}

Other considerations 其他注意事项

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.

相关问题 用户可以查看每个人的个人资料,但只能编辑自己的个人资料,如何在 Shiro 中实现? - User can view everyone's profile but only edit its own, how to implement in Shiro? 如何通过分页允许某些用户仅在 Spring Boot / Spring Security 的端点中访问他自己的数据? - How to allow some User only access his own data in endpoint in Spring Boot / Spring Security with pagination? 如何连接到Spring的@RequestBody参数解析,以使用请求的主体解析我自己的参数 - How can I hook into Spring's @RequestBody argument resolving to resolve my own argument using the body of the request 如何在春季只为一个用户角色启用X.509相互认证? - How can I enable X.509 mutual authentification for only one user role in spring? 如何保证汇集的AKKA演员仅从其自己的子演员发送和接收? - How can I guarantee a pooled AKKA actor only sends and receives from it's own child actor? 我可以将自己的User对象推送到Spring的SecurityContext吗? - Can I push my own User object into Spring's SecurityContext? 如何在不删除 Actuator 的情况下在 Spring Boot 中开发我自己的 /env 端点? - How can I develop my own /env endpoint in Spring Boot without remove Actuator? 如果我重用在 vertx 端点中向外部服务发出请求的自定义客户端,一个请求中的用户异常会阻止另一个用户的异常吗? - If I reuse a custom client that makes requests to an external service in an vertx endpoint, will user exceptions in one request block another user's? 如何在我的 Android 应用程序中使用用户自己的短信服务发送 OTP 并进行手机号码验证? - How can I use a user's own SMS service to send OTP and make mobile number verification in my Android app? 如何在日期选择器 Android 中仅启用特定日期? - How can I enable only specific days in datepicker Android?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM