如何使用 OAuth 和 OpenID Connect 验证每个用户可以访问哪些资源? [英] How to verify which resources each user can access with OAuth and OpenID Connect?

查看:14
本文介绍了如何使用 OAuth 和 OpenID Connect 验证每个用户可以访问哪些资源?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设我们有一些 RESTful API,我们想要公开其资源.最终用户将通过客户端应用程序(如移动应用程序和在 Web 浏览器上运行的基于 Javascript 的客户端)使用此 API.

使用 OAuth 2.0,这个 RESTful API 将位于资源服务器上,我们将拥有一个授权服务器,客户端应用程序在其上注册.然后,用户将在授权服务器上注册,并且能够为这些应用程序授予或不代表他们访问资源的权限.

因此,当用户访问一个客户端应用程序时,他将被重定向到授权服务器并被提示授予该客户端应用程序的权限.之后,会发出访问令牌,客户端就可以向资源服务器发出请求.

所有这些对我来说都很清楚.只有一个缺失:对每个资源的保护可能取决于用户.更准确地说,它可能取决于声明.我的意思是我们可以有以下情况:

当我第一次听说 OAuth 是在处理 ASP.NET WebAPI 时,我是这样处理的:当请求使用 Authorization: Bearer [token] 标头发送时,在服务器上一边设置了线程主体,我认为这意味着用户已通过 API 进行身份验证.所以我使用了 [Authorize] 属性来验证用户是否可以访问资源.

在更深入地研究 OAuth 之后,我发现这是对协议的严重滥用.据我所知,OAuth 授权应用程序而不是用户.当使用 Authorization 标头发出请求时,正如我所了解的,访问令牌不应包含有关用户的信息,而应包含有关允许发出请求的应用程序的信息.

考虑到这一点,发送带有请求的 Authorization 标头不会识别用户,也不会说明用户是否可以访问所述资源.

这种情况下,如何进行这种授权?我的意思是,不是授权执行请求的客户端应用程序,而是根据用户的声明访问资源的授权?我相信这是 OpenID Connect 及其 ID 令牌的用武之地,但我不确定.如何管理这一点?

解决方案

访问令牌不包含用户的声明,但包含已授予客户端应用程序权限的用户的主题.主题"是一个技术术语,表示唯一标识符.简单地说,主题"是您数据库中的用户 ID.

在受保护的资源端点,您将:

  1. 从请求中提取访问令牌.(RFC 6750)
  2. 从授权服务器获取有关访问令牌的详细信息.(RFC 7662)
  3. 验证访问令牌.验证包括 (a) 访问令牌是否已过期,以及 (b) 访问令牌是否涵盖受保护资源端点所需的范围(权限).

上面从 1 到 3 的步骤是对客户端应用程序的访问控制.OAuth 2.0(RFC 6749)就是为了这个.请参阅受保护资源"由 Authlete(由我提供)了解有关这些步骤的详细信息.

完成上述步骤后,您将:

  1. 从访问令牌中提取主题.再次,主题"是用户的唯一标识符.
  2. 从您的数据库中检索用户的声明.
  3. 根据需要验证声明.

上面从 4 到 6 的步骤是对用户的访问控制.OAuth 2.0 不适用于此.

OpenID Connect 的主要目的是获得一个 ID 令牌 以可验证的方式.您可以通过验证附加到 ID 令牌的签名来确认 ID 令牌已由正确的一方颁发.有关签名的详细信息,请参阅 JSON 网络签名 (JWS)(RFC 7515).>

ID 令牌本身不是保护 Web API 的技术.但是,如果您在 ID 令牌中正确使用 at_hash 声明(请参阅3.1.3.6. ID 令牌"在 OpenID Connect Core 1.0).但是,在受保护的资源端点,直接从数据库获取声明要比解析 ID 令牌容易得多.


**[ 评论的附加答案 #1 ]**

在您的用例中,您不需要 ID 令牌.这是因为访问令牌已经包含有关用户主题的信息.在正常情况下,该信息相当于 ID 令牌中 sub 声明的值.

因此,您不需要 ID 令牌来获取用户的主题.参见第 4 步的描述,您可以找到从访问令牌中提取主题".


**[ 评论的附加答案 #2 ]**<块引用>

那么从访问令牌中提取主题并验证声明有什么问题吗?或者这是正确的做事方式?

没有任何问题.例如,假设您定义了一个 Web API,https://api.example.com/profile,它返回用户的个人资料信息.在正常情况下,这样的 API 会接受访问令牌,然后从访问令牌中提取主题以确定要引用哪个用户.另一方面,如果 API 没有从访问令牌中提取主题,则它必须要求主题"作为请求参数来确定要引用哪个用户(或需要包含sub"声明的 ID 令牌).即使在这种情况下,API 也必须检查请求参数指定的主题和访问令牌关联的主题是否相同,否则就会成为安全问题.

提取主题后检查声明也是正常步骤.例如,您可能希望根据用户支付的计划(免费计划、轻量计划、企业计划或其他计划)限制服务的功能.在这种情况下,您必须参考 plan 声明.当然,只有在从访问令牌中提取主题后才能检查这样的声明.

因此,(1) 从访问令牌中提取主题,然后 (2) 验证用户的声明是受保护资源端点实现中的正常甚至典型步骤.

Suppose we have some RESTful API whose resources we want to expose. End users will work with this API through client applications like mobile apps and Javascript based clients that run on web browsers.

With OAuth 2.0 this RESTful API will lie on the Resource Server and we will have one Authorization Server on which the client applications are registered. The users will then be registered at the authorization server and will be able to grant permission to those applications access resources on their behalf or not.

So when the user access one client application he will be redirected to the Authorization Server and be prompted to grant permissions to said client app. After that an access token is issued and the client is able to make requests to the Resource Server.

All of this is quite clear to me. There's just one missing piece: the protection of each resource might be user-dependent. To be more precise it might be claims-dependent. What I mean by that is we can have the following situation:

When I first heard of OAuth was dealing with ASP.NET WebAPI and I dealt with that in the following way: when the request was sent with the Authorization: Bearer [token] header, on server side the thread principal was set and I thought that this meant the user was authenticated with the API. So I used [Authorize] attributes in order to verify if the user could access the resource.

After studying OAuth more deeply I saw this was a terrible misuse of the protocol. As I've learned, OAuth authorizes applications and not users. When the request is made with the Authorization header, as I've learned, the access token shouldn't contain information about the user, just about the application being allowed to make the request.

Considering that, sending the Authorization header with the request doesn't identify the user and does don't say if the user can or cannot access said resource.

In that case, how does one perform this kind of authorization? I mean, not authorization of the client app performing the request, but the authorization of the user accessing the resource based on his claims? I believe this is where OpenID Connect and it's ID tokens come in, but I'm unsure. How does one manage this?

解决方案

An access token does not contain a user's claims, but it contains the subject of the user who has granted permissions to the client application. "Subject" is a technical term and it means a unique identifier. Simply saying, "subject" is a user ID in your database.

At a protected resource endpoint, you will do:

  1. Extract an access token from the request. (RFC 6750)
  2. Get detailed information about the access token from the authorization server. (RFC 7662)
  3. Validate the access token. The validation includes (a) whether the access token has expired or not, and (b) whether the access token covers scopes (permissions) that are required by the protected resource endpoint.

The steps above from 1 to 3 are an access control against client applications. OAuth 2.0 (RFC 6749) is for this. See "Protected Resource" by Authlete (by me) for details about these steps.

After the steps above, then you will do:

  1. Extract the subject from the access token. Again, "subject" is a unique identifier of the user.
  2. Retrieve claims of the user from your database.
  3. Validate the claims as you like.

The steps above from 4 to 6 are an access control against users. OAuth 2.0 is NOT for this.

The primary purpose of OpenID Connect is to get an ID token in a verifiable manner. You can confirm that an ID token has been issued by the right party by verifying the signature attached to the ID token. See JSON Web Signature (JWS) (RFC 7515) for details about signature.

An ID token itself is not a technology to protect Web APIs. But you may be able to use it for that purpose if you use at_hash claim in an ID token properly (see "3.1.3.6. ID Token" in OpenID Connect Core 1.0). However, at a protected resource endpoint, it will be much easier to get claims directly from your database than to parse an ID token.


**[ Additional answer #1 for the comment ]**

In your use case, you don't need ID tokens. It's because an access token already contains information about the subject of the user. In normal cases, the information is equivalent to the value of sub claim in an ID token.

Therefore, you don't need an ID token to get the subject of the user. See the description of step 4, and you can find "extract the subject from the access token."


**[ Additional answer #2 for the comment ]**

So is there anything wrong in extracting the subject from the access token like that and verify the claims? Or this is the right way of doing things?

There is nothing wrong. For example, suppose you define a Web API, https://api.example.com/profile, which returns the profile information of a user. In normal cases, such an API would accept an access token and then extract the subject from the access token to determine which user to refer to. On the other hand, if the API did not extract the subject from the access token, it would have to require "subject" as a request parameter to determine which user to refer to (or require an ID token that contains "sub" claim). Even in such a case, the API must check whether the subject specified by the request parameter and the subject associated with the access token are identical because otherwise, it would become a security issue.

Checking claims after extracting the subject is also a normal step. For example, you may want to restrict the functionalities of your service based on the plan that the user has paid for (Free plan, Lite plan, Enterprise plan, or whatever). In this case, you would have to refer to plan claim. Of course, checking such a claim can be done only after extracting the subject from the access token.

Therefore, (1) extracting the subject from an access token and then (2) verifying the claims of the user are normal and even typical steps in implementations of protected resource endpoints.

这篇关于如何使用 OAuth 和 OpenID Connect 验证每个用户可以访问哪些资源?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆