OAuth 2.0 认证示例
概述
本教程风格的指南有两个主要目标:
- 探索应用程序和最终用户如何使用 OAuth 2.0 而非传统的用户名/密码或 x.509 证书认证 RabbitMQ 服务器。
- 探索如何在多个授权服务器上设置 RabbitMQ Server 的 OAuth 2.0 认证机制。
本指南附带公共 GitHub 仓库,其中包含部署指南中演示的示例所需的所有脚本。
目录
基础知识
管理 UI 访问
使用多种协议中的 JWT 令牌访问 RabbitMQ
- Management REST API
- AMQP 0-9-1(以及在单独部分中用于主题交换的范围)
- AMQP 1.0
- JMS
- MQTT
签名密钥、范围别名、富授权请求
特定 OAuth 2.0 身份提供商的示例
- Keycloak
- Auth0
- Microsoft Entra ID(以前称为 Azure Active Directory)
- OAuth2 Proxy
- Okta
- Google 不支持
- 多个 OAuth 2.0 服务器和/或受众
Tanzu RabbitMQ 的示例(仅限商业功能)
本指南中示例使用的前提条件
- 必须安装 Docker
- 必须安装 Ruby
- make
- 克隆一个GitHub 仓库的本地副本(分支为
next),其中包含此示例中使用的所有配置文件和脚本。 - 您的
/etc/hosts文件中必须包含以下条目:
127.0.0.1 localhost uaa rabbitmq
开始使用 UAA 和 RabbitMQ
要演示 OAuth 2.0,您至少需要一个 OAuth 2.0 授权服务器以及为选定的授权服务器正确配置的 RabbitMQ。本指南使用UAA 作为授权服务器,来演示访问管理 UI 和各种消息传递协议的基本和高级配置。
本指南还演示了如何将 RabbitMQ 配置为使用UAA 以外的其他授权服务器,例如Keycloak。本指南的目录包含所有授权服务器的完整列表。
运行以下两个命令来启动为 UAA 配置的 UAA 和 RabbitMQ
make start-uaa启动 UAA 服务器make start-rabbitmq启动 RabbitMQ 服务器
最后一个命令启动一个 RabbitMQ,使用特定的配置文件 rabbitmq.conf。
使用 OAuth 2.0 令牌访问管理 UI
RabbitMQ Management UI 可以配置为以下两种登录模式之一:
- 服务提供商发起的登录:这是默认的传统 OAuth 2.0 登录模式。当用户访问 RabbitMQ Management UI 时,会显示一个带有标签
Click here to logon的按钮。当用户单击它时,登录过程将通过重定向到配置的授权服务器来启动。 - 身份提供商发起的登录:此模式与前一种模式相反。用户必须先使用令牌访问 RabbitMQ Management 的
/login端点。如果令牌有效,则允许用户访问 RabbitMQ Management UI。此模式对于允许用户单击一次即可访问 RabbitMQ Management UI 的网站非常有用。原始网站会代表用户获取令牌,然后将用户重定向到 RabbitMQ Management 的/login端点。
服务提供商发起的登录
当最终用户首次访问管理 UI 时,他们会被重定向到配置的 OAuth 2.0 提供商进行身份验证。成功认证后,用户会带着有效的访问令牌重定向回 RabbitMQ。RabbitMQ 会验证令牌,并从中识别用户及其权限。
[ UAA ] <----2. auth---- [ RabbitMQ ]
----3. redirect--> [ http ]
/|\
|
1. rabbit_admin from a browser
在步骤 2 中,如果这是用户首次访问 RabbitMQ 资源,UAA 将提示用户授权 RabbitMQ 应用程序,如下图所示。

UAA 已预先配置了两个用户:
rabbit_admin:rabbit_admin- 以及
rabbit_monitor:rabbit_monitor
首先访问https://uaa:8443,以便您的浏览器可以信任 uaa 的自签名证书。否则,管理 UI 将无法连接到 uaa。
现在导航到本地节点的管理 UI,并使用这两个用户之一进行登录。
这是 UAA 为 rabbit_admin 用户通过您刚才看到的重定向流程颁发的令牌。它使用对称密钥进行了签名。

要使用 OAuth 2.0 配置 RabbitMQ Management UI,需要在 rabbitmq.conf 中设置以下配置项:
# ...
management.oauth_enabled = true
management.oauth_client_id = rabbit_client_code
auth_oauth2.issuer = https://uaa:8443
# ...
只有当您未配置 auth_oauth2.issuer 并且/或者它们具有不同的 URL 时,才需要设置 management.oauth_provider_url。
身份提供商发起的登录
与服务提供商发起的登录一样,通过 Idp 发起的登录,用户可以带着有效的令牌访问 RabbitMQ Management UI。以下场景是 Idp 发起登录的示例:
- RabbitMQ 位于一个 Web 门户后面,该门户方便用户直接访问完全认证的 RabbitMQ。
- 在用户和 RabbitMQ 之间有一个 OAuth2 代理,它会拦截用户的请求,并将请求转发给 RabbitMQ,同时在 HTTP
Authorization标头中插入令牌。
后一种场景在此处演示。前一种场景将在下一节中介绍。
通过登录端点进行 Idp 发起登录
Web 门户向其已认证的用户提供导航到 RabbitMQ 的选项,通过提交一个表单,其中 access_token 表单字段包含 OAuth 令牌,如下所示。
[ Idp | WebPortal ] ----> 2. /login [access_token: TOKEN]---- [ RabbitMQ Cluster ]
/|\ |
| |
1. rabbit_admin from a browser <-----3. 302 redirect to RabbitMQ w/cookie--+
如果访问令牌有效,RabbitMQ 会将用户重定向到概览页面,并附带一个包含已验证令牌的 cookie。当 RabbitMQ 提供概览页面时,它会清除该 cookie。
默认情况下,RabbitMQ Management UI 配置为服务提供商发起的登录。要配置身份提供商发起的登录,需要在 rabbitmq.conf 中设置以下配置项:
# ...
management.oauth_enabled = true
management.oauth_initiated_logon_type = idp_initiated
management.oauth_provider_url = https://:8080
# ...
只有当您未配置 auth_oauth2.issuer 并且/或者它们具有不同的 URL 时,才需要设置 management.oauth_provider_url。
重要提示:当用户注销、其 RabbitMQ 会话过期或令牌过期时,用户将被导向 RabbitMQ Management 登陆页面,该页面有一个单击此处登录按钮。用户永远不会自动重定向回 auth_oauth2.issuer 中配置的 URL。只有当用户单击单击此处登录时,用户才会被重定向到 auth_oauth2.issuer 中配置的 URL。
此场景在此处演示。
在多种协议中使用 JWT 令牌访问 RabbitMQ
以下子章节演示了如何在任何消息传递协议中使用访问令牌以及如何访问管理 HTTP API。
Management REST API
在此场景中,一个监控代理使用 RabbitMQ HTTP API 来收集监控信息。因为它不是最终用户或人类,所以我们称之为服务账户。这个服务账户可以是我们在 UAA 中创建的、具有 monitoring用户标签的 mgt_api_client 客户端。
这个监控代理将使用客户端凭据或密码授权流与 UAA 进行身份验证 (1),然后获取 JWT 令牌 (2)。一旦获得令牌,它将发送 (3) 一个 HTTP 请求到 RabbitMQ 管理端点,并将 JWT 令牌作为Bearer 令牌包含在 Authorization 标头中。
[ UAA ] [ RabbitMQ ]
/|\ [ http ]
| /|\
| 3.http://broker:15672/api/overview passing JWT token
| |
+-----1.auth--------- monitoring agent
--------2.JWT-------->
以下命令启动浏览器,使用 mgt_api_client 客户端和从 UAA 之前获得的 JWT 令牌。
make curl-uaa url=https://:15672/api/overview client_id=mgt_api_client secret=mgt_api_client
AMQP 协议
应用程序通过 AMQP 协议连接到 RabbitMQ,并以 JWT 令牌作为凭据。您将使用的应用程序是PerfTest,它不是一个 OAuth 2.0 感知的应用程序。OAuth 2.0 感知的应用程序将在场景四中介绍。
相反,您将使用之前从 UAA 获取的令牌启动应用程序。这只是为了通过 JWT 令牌探测 AMQP 访问。Needless to say that the application should instead obtain the JWT Token prior to connecting to RabbitMQ and it should also be able to refresh it before reconnecting. RabbitMQ validates the token before accepting it. If the token has expired, RabbitMQ will reject the connection. (这意味着,应用程序在连接到 RabbitMQ 之前应该获取 JWT 令牌,并且在重新连接之前能够刷新它。RabbitMQ 会在接受令牌之前对其进行验证。如果令牌已过期,RabbitMQ 将拒绝连接。)
首先,一个想要使用 Oauth 2.0 连接到 RabbitMQ 的应用程序必须提供一个有效的 JWT 令牌。要获取令牌,应用程序必须首先与 UAA 进行身份验证 (1.)。如果身份验证成功,它将获得一个 JWT 令牌 (2.),然后使用该令牌连接 (3.) 到 RabbitMQ。
[ UAA ] [ RabbitMQ ]
/|\ [ amqp ]
| /|\
| 3.connect passing JWT
| |
+-----1.auth--------- amqp application
--------2.JWT-------->
您之前已配置 UAA 使用这两个 OAuth 2.0 客户端:
consumerproducer
为了获得 JWT 令牌,必须使用 OAuth 2.0 客户端。应用程序使用 Oauth client grant flow 来获取 JWT 令牌。
这是 UAA 为 consumer OAuth 2.0 客户端颁发的令牌。

要启动 consumer 应用程序,请调用以下命令:
make start-perftest-consumer
查看 consumer 日志
docker logs consumer -f
要启动 producer 应用程序,请调用以下命令:
make start-perftest-producer
检查 producer 日志
docker logs producer -f
调用以下命令停止所有应用程序:
make stop-all-apps
JMS 协议
在此用例中,您正在演示一个基本的 JMS 应用程序,该应用程序通过环境变量 (TOKEN) 读取 JWT 令牌,该令牌将用作向 RabbitMQ 进行身份验证时的密码。
至关重要的是,授予对交换器 jms.durable.queues 所需的权限。
发送 JMS 消息的应用程序需要以下权限:
rabbitmq.configure:*/jms.durable.queuesrabbitmq.write:*/jms.durable.queuesrabbitmq.read:*/jms.durable.queues
这些权限授予对所有虚拟主机的访问权限。
在测试 publisher 和 subscriber 应用程序之前,需要通过调用此命令来为基本 jms 应用程序构建本地镜像:
make build-jms-client
要测试一个发送消息并进行 OAuth 2.0 身份验证的 JMS 应用程序,请运行此命令:
make start-jms-publisher
它会将消息发送到名为 q-test-queue 的队列。
订阅 JMS 队列的应用程序需要以下权限:
rabbitmq.write:*/jms.durable.queues
这些权限授予对所有虚拟主机的访问权限。
要测试一个订阅队列并进行 OAuth 2.0 身份验证的 JMS 应用程序,请运行此命令:
make start-jms-subscriber
它会订阅名为 q-test-queue 的队列。
MQTT 协议
本场景探讨了使用 JWT 令牌向 RabbitMQ MQTT 端口进行身份验证的用例。
注意:在此示例中,RabbitMQ 已配置了rabbitmq_mqtt 插件。
这与使用 AMQP 或 JMS 协议没有区别,唯一重要的是传递一个空的用户名和一个 JWT 令牌作为密码。然而,真正不同之处在于如何编码权限。在此用例中,您将按照上一个用例中的方法进行,即手工制作 JWT 令牌而不是向 UAA 请求。以下是发布消息到 mqtt 主题所需的作用域(scopes-for-mqtt.json)。
{
"scope": [
"rabbitmq.write:*/*/*",
"rabbitmq.configure:*/*/*",
"rabbitmq.read:*/*/*"
],
"extra_scope": "rabbitmq.tag:management",
"aud": [
"rabbitmq"
]
}
rabbitmq.write:*/*/* 表示允许在任何 vhost、任何交换器和任何主题上进行写入操作。实际上,它指的是任何“路由键”,因为这会被转换为主题/队列。
您将通过运行以下命令来发布 mqtt 消息。如果您没有运行任何之前的用例,您需要像这样启动 RabbitMQ:make start-rabbitmq。
make start-mqtt-publish TOKEN=$(bin/jwt_token scopes-for-mqtt.json legacy-token-key private.pem public.pem)
重要提示:如果您尝试使用 rabbit_admin 在 UAA 中访问管理 UI 并进行身份验证,您将无法将队列绑定到路由键
test和交换器amq.topic,因为 UAA 中的该用户没有必要的权限。在我们的手工制作的令牌中,您已经授予了我们正确的权限/范围。
AMQP 1.0 协议
在此用例中,您正在演示一个基本的 AMQP 1.0 应用程序,该应用程序从 PASSWORD 环境变量中读取 JWT 令牌。然后,该应用程序在向 RabbitMQ 进行身份验证时将该令牌用作密码。
在测试 publisher 和 subscriber 应用程序之前,需要通过调用此命令来为基本 AMQP 1.0 应用程序构建本地镜像:
make build-amqp1_0-client
使用以下命令启动 RabbitMQ。它将启动已配置 UAA 作为其授权服务器的 RabbitMQ。
make start-rabbitmq
启动 UAA
make start-uaa
并发送一条消息。它使用 UAA 中声明的客户端 ID jms_producer 来获取令牌。
make start-amqp1_0-publisher
使用主题交换器
本节解释了使用主题交换器的应用程序需要哪些范围。
本教程提供的任何授权服务器中声明的用户和/或客户端都没有主题交换器的适当范围。在MQTT 部分,应用程序使用了具有适当范围的手工制作的令牌,因为该协议的路由完全基于主题。
要将队列绑定/解绑到/从主题交换器,您需要拥有以下范围:
| 权限 | 示例 |
对队列和路由键的写入权限 -> rabbitmq.write:<vhost>/<queue>/<routingkey> | rabbitmq.write:*/*/* |
对交换器和路由键的读取权限 -> rabbitmq.write:<vhost>/<exchange>/<routingkey> | rabbitmq.read:*/*/* |
| 权限 | 示例 |
对交换器和路由键的写入权限 -> rabbitmq.write:<vhost>/<exchange>/<routingkey> | rabbitmq.write:*/*/* |
OAuth 2.0 授权后端支持在检查主题权限时进行变量扩展。它支持任何值为纯字符串的 JWT 声明以及 vhost 变量。
例如,如果用户使用下面的令牌连接到 vhost prod,他们应该有写入权限,可以发送到任何以 x-prod- 开头的交换器和任何以 u-bob- 开头的路由键。
{
"sub" : "bob",
"scope" : [ "rabbitmq.write:*/q-{vhost}-*/u-{sub}-*" ]
}
高级 OAuth 2.0 配置主题
使用自定义范围字段
有些授权服务器无法将 RabbitMQ 范围包含在标准的 JWT scope 字段中。相反,它们可以将 RabbitMQ 范围包含在它们选择的自定义 JWT 范围中。
可以使用如下所示的配置,使用不同的字段来查找范围:
...
auth_oauth2.additional_scopes_key = extra_scope
...
要测试此功能,您将构建一个令牌,对其进行签名,然后使用它来访问 RabbitMQ 的管理端点之一。下面的命令允许我们使用令牌来访问任何管理端点,在本例中是 overview。
make curl-with-token URL=https://:15672/api/overview TOKEN=$(bin/jwt_token scope-and-extra-scope.json legacy-token-key private.pem public.pem)
您可以使用 Python 脚本 bin/jwt_token.py 来构建 RabbitMQ 能够验证的最小 JWT 令牌,即:
{
"scope": [
],
"extra_scope": [
"rabbitmq.tag:management"
],
"aud": [
"rabbitmq"
]
}
使用多个非对称签名密钥
此场景探讨了 JWT 令牌可能由不同非对称签名密钥签名的用例。
有两种方法可以将 RabbitMQ 配置为使用多个签名密钥:
- 通过
rabbitmq.conf静态配置它们,如插件文档页面所示。 - 动态地将密钥添加到正在运行的 RabbitMQ 节点,而无需重启。
首先,您添加第二个签名密钥,名为 legacy-token-2-key,其公钥为 conf/public-2.pem。
docker exec -it rabbitmq rabbitmqctl add_signing_key legacy-token-2-key --pem-file=/conf/public-2.pem
Adding OAuth signing key "legacy-token-2-key" filename: "/conf/public-2.pem"
然后,您使用相应的私钥颁发令牌,并使用它来访问管理端点 /api/overview。
make curl-with-token URL=https://:15672/api/overview TOKEN=$(bin/jwt_token scope-and-extra-scope.json legacy-token-2-key private-2.pem public-2.pem)
bin/jwt_token 在 conf 目录中搜索私钥和公钥文件,在 jwts 目录中搜索 jwt 文件。
使用范围别名
此示例演示了如何将自定义范围与 RabbitMQ 结合使用。
UAA 身份提供商已配置了两个客户端(producer_with_roles 和 consumer_with_roles),具有以下自定义范围:
producer_with_roles 拥有:
api://rabbitmq:producer.
consumer_with_roles 拥有:
api://rabbitmq:Read.All.api://rabbitmq:Write.All.api://rabbitmq:Configure.All.api://rabbitmq:Administrator.
有关范围别名的更多信息,请查看本节,其中有更详细的解释。
如何配置范围别名
这是将这些自定义范围映射到 RabbitMQ 范围所需的配置。
自 RabbitMQ 4.1 起,可以使用类似 ini 的配置样式来配置范围别名。早期版本仅支持传统的 Erlang 风格。
auth_oauth2.scope_aliases.1.alias = api://rabbitmq:Read.All
auth_oauth2.scope_aliases.1.scope = rabbitmq.read:*/*
auth_oauth2.scope_aliases.2.alias = api://rabbitmq:Write.All
auth_oauth2.scope_aliases.2.scope = rabbitmq.write:*/*
auth_oauth2.scope_aliases.3.alias = api://rabbitmq:Configure.All
auth_oauth2.scope_aliases.3.scope = rabbitmq.configure:*/*
auth_oauth2.scope_aliases.3.alias = api://rabbitmq:Administrator
auth_oauth2.scope_aliases.3.scope = rabbitmq.tag:administrator
auth_oauth2.scope_aliases.4.alias = api://rabbitmq:producer
auth_oauth2.scope_aliases.4.scope = rabbitmq.read:*/* rabbitmq.write:*/* rabbitmq.configure:*/* rabbitmq.tag:management
RabbitMQ 配置
在 OAuth 2.0 教程存储库中,有两个 RabbitMQ 配置文件可供 UAA 使用:
- conf/uaa/advanced-scope-aliases.config:配置了一组范围别名。
- conf/uaa/rabbitmq.conf:除了配置
extra_scope作为另一个可以读取范围的声明外,还配置了其余的 oauth2 配置。
演示 1:使用作用域字段中的自定义作用域启动 RabbitMQ
要使用作用域映射并在作用域字段中使用自定义作用域启动 RabbitMq,请运行以下命令:
ADVANCED=advanced-scope-aliases.config make start-rabbitmq
此命令将在 RabbitMQ 已运行时将其停止。
使用客户端 producer_with_roles 启动 producer 应用程序。
make start-perftest-producer PRODUCER=producer_with_roles
检查日志
docker logs producer_with_roles -f
使用客户端 consumer_with_roles 启动 consumer 应用程序。
make start-perftest-consumer CONSUMER=consumer_with_roles
检查日志:docker logs consumer_with_roles -f
使用客户端 producer_with_roles 访问管理 API。
make curl url=https://:15672/api/overview client_id=producer_with_roles secret=producer_with_roles_secret
要停止 perf-test 应用程序,请运行:
make stop-perftest-producer PRODUCER=producer_with_roles
make stop-perftest-consumer CONSUMER=consumer_with_roles
演示 2:使用 extra scope 字段中的自定义范围启动 RabbitMQ
要使用作用域映射并在 extra_scope 字段中使用自定义作用域启动 RabbitMq,请运行以下命令:
make start-rabbitmq
此命令将在 RabbitMQ 已运行时将其停止。
您无法使用 UAA 发行令牌,因为您无法将 UAA 配置为对范围使用自定义字段。相反,您将使用 bin/jwt_token 命令自行发行令牌。
使用令牌 producer-role-in-scope.json 启动 producer 应用程序。
make start-perftest-producer-with-token PRODUCER=producer_with_roles TOKEN=$(bin/jwt_token producer-role-in-extra-scope.json legacy-token-key private.pem public.pem)
检查日志
docker logs producer_with_roles -f
使用令牌 consumer-roles-in-extra-scope.json 启动 consumer 应用程序。
make start-perftest-consumer-with-token CONSUMER=consumer_with_roles TOKEN=$(bin/jwt_token consumer-roles-in-extra-scope.json legacy-token-key private.pem public.pem)
使用令牌 producer-roles-in-extra-scope.json 访问管理 API。
make curl-with-token URL="https://:15672/api/overview" TOKEN=$(bin/jwt_token producer-roles-in-extra-scope.json legacy-token-key private.pem public.pem)
要停止 perf-test 应用程序,请运行:
make stop-perftest-producer PRODUCER=producer_with_roles
make stop-perftest-consumer CONSUMER=consumer_with_roles
在范围中使用变量扩展
有时,在以下任一地方定义使用变量的作用域会很方便:
- 作用域的 vhost 部分
- 资源和/或路由键部分
变量名可以是 vhost(其值与您正在访问的 vhost 匹配),或者令牌中的任何单个值声明,例如 user_name。
为了演示此功能:
- 按照Keycloak 中的步骤启动 Keycloak OAuth 提供商和 RabbitMQ。Keycloak 已配置为使用范围
rabbitmq.configure:*/q-{user_name}颁发令牌。 - 使用用户名
rabbit_admin登录到https://:15672的管理 UI。 - 尝试创建一个名为
test的队列。预计会因授权错误而失败。 - 创建一个名为
q-rabbit_admin的队列。预计会被允许这样做。
RabbitMQ 中无需进行任何配置,但版本必须是 RabbitMQ 4.1.1 或更高版本。
首选用户名声明
RabbitMQ 需要确定与令牌关联的用户名,以便在管理 UI 中显示。默认情况下,RabbitMQ 首先查找 sub 声明,如果找不到,则使用 client_id。
大多数授权服务器返回用户的 GUID 而不是实际的用户名或电子邮件地址(用户可以关联的任何信息)。当 sub 声明不包含用户友好的用户名时,您可以配置一个或多个声明来从令牌中提取用户名。
给定此配置:
...
auth_oauth2.resource_server_id = rabbitmq
auth_oauth2.preferred_username_claims.1 = user_name
auth_oauth2.preferred_username_claims.2 = email
...
RabbitMQ 首先查找 user_name 声明,如果找不到,则查找 email。否则,它会使用默认的查找机制,该机制首先查找 sub,然后查找 client_id。
使用富授权请求令牌
Rich Authorization Request 扩展提供了一种 OAuth 2.0 客户端在授权请求期间请求细粒度权限的方法。它摆脱了范围作为文本标签的概念,而是定义了一个更复杂的权限模型。
RabbitMQ 支持符合该扩展的 JWT 令牌。下面是 JWT 令牌的示例部分:
{
"authorization_details": [
{ "type" : "rabbitmq",
"locations": ["cluster:finance/vhost:primary-*"],
"actions": [ "read", "write", "configure" ]
},
{ "type" : "rabbitmq",
"locations": ["cluster:finance", "cluster:inventory", ],
"actions": ["tag:administrator" ]
}
]
}
准备环境
要演示此新功能,您必须使用 conf/uaa/rabbitmq-for-rar-tokens.config 下的相应配置文件部署 RabbitMQ。
export CONFIG=rabbitmq-for-rar-tokens.config
make start-rabbitmq
注意:您无需运行任何 OAuth 2.0 服务器,如 UAA。这是因为您将使用 RabbitMQ 配置的相同公私钥对来创建和签名令牌。
使用富授权令牌访问管理 HTTP API
您将使用此令牌 jwts/rar-token.json 来访问管理 HTTP API 的端点。
make curl-with-token URL=https://:15672/api/overview TOKEN=$(bin/jwt_token rar-token.json legacy-token-key private.pem public.pem)
注意:您正在使用 curl 来访问 URL,并使用您使用 bin/jwt_token 命令构建的 TOKEN。该命令接受 JWT 载荷、签名密钥的名称以及用于签名令牌的私钥和公钥证书。
使用富授权令牌进行应用程序认证和授权
这次,您将使用与上一个部分相同的令牌来通过充当 AMQP producer 应用程序的 PerfTest 工具访问 AMQP 协议。
make start-perftest-producer-with-token PRODUCER=producer_with_roles TOKEN=$(bin/jwt_token rar-token.json legacy-token-key private.pem public.pem)
上面的命令会在后台启动应用程序,您可以通过运行以下命令来检查日志:
docker logs producer_with_roles -f
有关此新功能的更多信息,请查看OAuth 2 指南。