19. 基于令牌的身份验证

OAuth 2 用于基于令牌的身份验证。您可以管理 OAuth 令牌以及应用程序,应用程序是用于生成令牌的 API 客户端的服务器端表示。通过在 HTTP 身份验证标头中包含 OAuth 令牌,您可以验证自己的身份并调整限制性权限的程度,此外还有基本 RBAC 权限。有关 OAuth 2 规范的更多详细信息,请参阅 RFC 6749

有关使用 manage 实用程序创建令牌的详细信息,请参阅 令牌和会话管理 部分。

19.1. 管理 OAuth 2 应用程序和令牌

应用程序和令牌可以在 /api/<version>/applications/api/<version>/tokens 处作为顶级资源进行管理。这些资源也可以在各自的用户处访问,例如 /api/<version>/users/N/<resource>。可以通过对 api/<version>/applications/api/<version>/users/N/applications 进行 POST 操作来创建应用程序。

每个 OAuth 2 应用程序都代表服务器端的一个特定 API 客户端。要让 API 客户端通过应用程序令牌使用 API,它必须首先拥有应用程序并发出访问令牌。可以通过主鍵访问各个应用程序:/api/<version>/applications/<pk>/。以下是一个典型的应用程序

    {
    "id": 1,
    "type": "o_auth2_application",
    "url": "/api/v2/applications/2/",
    "related": {
        "tokens": "/api/v2/applications/2/tokens/"
    },
    "summary_fields": {
        "organization": {
            "id": 1,
            "name": "Default",
            "description": ""
        },
        "user_capabilities": {
            "edit": true,
            "delete": true
        },
        "tokens": {
            "count": 0,
            "results": []
        }
    },
    "created": "2018-07-02T21:16:45.824400Z",
    "modified": "2018-07-02T21:16:45.824514Z",
    "name": "My Application",
    "description": "",
    "client_id": "Ecmc6RjjhKUOWJzDYEP8TZ35P3dvsKt0AKdIjgHV",
    "client_secret": "7Ft7ym8MpE54yWGUNvxxg6KqGwPFsyhYn9QQfYHlgBxai74Qp1GE4zsvJduOfSFkTfWFnPzYpxqcRsy1KacD0HH0vOAQUDJDCidByMiUIH4YQKtGFM1zE1dACYbpN44E",
    "client_type": "confidential",
    "redirect_uris": "",
    "authorization_grant_type": "password",
    "skip_authorization": false,
    "organization": 1
}

如上例所示,name 是应用程序的人类可读标识符。其余字段(如 client_idredirect_uris)主要用于 OAuth2 授权,这将在后面的 使用 OAuth 2 令牌系统进行个人访问令牌 (PAT) 中介绍。

client_idclient_secret 字段的值在创建过程中生成,并且是不可编辑的应用程序标识符,而 organizationauthorization_grant_type 在创建时是必需的,并且变为不可编辑的。

19.1.1. 应用程序访问规则

应用程序访问规则如下

  • 系统管理员可以查看和操作系统中的所有应用程序

  • 组织管理员可以查看和操作属于组织成员的所有应用程序

  • 其他用户只能查看、更新和删除他们自己的应用程序,但不能创建任何新的应用程序

另一方面,令牌是用于实际验证传入请求并掩盖底层用户权限的资源。有两种方法可以创建令牌

  • 使用 applicationscope 字段对 /api/v2/tokens/ 端点进行 POST 操作,以指向相关应用程序并指定令牌范围

  • 使用 scope 字段对 /api/v2/applications/<pk>/tokens/ 端点进行 POST 操作(父应用程序将自动链接)

可以通过主鍵访问各个令牌:/api/<version>/tokens/<pk>/。以下是一个典型的令牌示例

{
    "id": 4,
    "type": "o_auth2_access_token",
    "url": "/api/v2/tokens/4/",
    "related": {
        "user": "/api/v2/users/1/",
        "application": "/api/v2/applications/1/",
        "activity_stream": "/api/v2/tokens/4/activity_stream/"
},
    "summary_fields": {
        "application": {
            "id": 1,
            "name": "Default application for root",
            "client_id": "mcU5J5uGQcEQMgAZyr5JUnM3BqBJpgbgL9fLOVch"
        },
        "user": {
            "id": 1,
            "username": "root",
            "first_name": "",
            "last_name": ""
        }
    },
    "created": "2018-02-23T14:39:32.618932Z",
    "modified": "2018-02-23T14:39:32.643626Z",
    "description": "App Token Test",
    "user": 1,
    "token": "*************",
    "refresh_token": "*************",
    "application": 1,
    "expires": "2018-02-24T00:39:32.618279Z",
    "scope": "read"
},

对于 OAuth 2 令牌,唯一完全可编辑的字段是 scopedescription。更新时,application 字段不可编辑,所有其他字段完全不可编辑,并且在创建过程中自动填充,如下所示

  • user 字段对应于创建令牌的用户,在本例中,也是创建令牌的用户

  • expires 是根据 AWX 配置设置 OAUTH2_PROVIDER 生成的

  • tokenrefresh_token 是自动生成的,以确保不冲突的随机字符串

应用程序令牌和个人访问令牌都显示在 /api/v2/tokens/ 端点中。个人访问令牌中的 application 字段始终为 null。这是区分两种令牌类型的好方法。

19.1.2. 令牌访问规则

令牌访问规则如下

  • 如果用户能够查看相关应用程序,则用户可以创建令牌;并且还可以为自己创建个人令牌

  • 系统管理员能够查看和操作系统中的每个令牌

  • 组织管理员能够查看和操作属于组织成员的所有令牌

  • 系统审计员可以查看所有令牌和应用程序

  • 其他普通用户只能查看和操作他们自己的令牌

注意

用户只能在创建时查看令牌或刷新令牌值。

19.2. 使用 OAuth 2 令牌系统进行个人访问令牌 (PAT)

获取 OAuth 2 令牌最简单、最常用的方法是在 /api/v2/users/<userid>/personal_tokens/ 端点创建个人访问令牌,如以下示例所示

curl -H "Content-type: application/json" -d '{"description":"Personal AWX CLI token", "application":null, "scope":"write"}' https://<USERNAME>:<PASSWORD>@<AWX_SERVER>/api/v2/users/<USER_ID>/personal_tokens/ | python -m json.tool

如果已安装,您也可以通过 jq 传递 JSON 输出。

以下是使用个人令牌访问 API 端点(使用 curl)的示例

curl -H "Authorization: Bearer <token>" -H "Content-Type: application/json" -d '{}' https://awx/api/v2/job_templates/5/launch/

在 AWX 中,OAuth 2 系统构建在 Django Oauth Toolkit 之上,该工具提供了专门用于授权、吊销和刷新令牌的端点。这些端点位于 /api/v2/users/<USER_ID>/personal_tokens/ 端点下,该端点还提供了有关这些端点的一些典型使用方法的详细示例。这些特殊的 OAuth 2 端点仅支持使用 x-www-form-urlencoded Content-type,因此 api/o/* 端点都不接受 application/json

注意

您也可以通过将 null 指定为应用程序类型来使用 /api/o/token 端点请求令牌。

或者,您可以通过 AWX 用户界面 添加令牌,以及配置访问令牌及其关联的刷新令牌(如果适用)的过期时间。

../_images/configure-awx-system-misc-sys-token-expire.png

19.2.1. 令牌范围掩码在 RBAC 系统之上

OAuth 2 令牌的范围是由有效范围关键字“read”和“write”组成的空格分隔字符串。这些关键字是可配置的,用于指定经过身份验证的 API 客户端的权限级别。读写范围在 AWX 的基于角色的访问控制 (RBAC) 权限系统之上提供了一个掩码层。具体来说,“write”范围赋予经过身份验证的用户 RBAC 系统提供的全部权限,而“read”范围仅赋予经过身份验证的用户 RBAC 系统提供的只读权限。请注意,“write”也意味着“read”。

例如,如果您对某个作业模板具有管理权限,那么如果您通过会话或基本身份验证进行身份验证,则可以查看、修改、启动和删除该作业模板。相反,如果您使用 OAuth 2 令牌进行身份验证,并且相关令牌范围为“read”,则即使您是管理员,您也只可以查看,而不能操作或启动该作业模板。如果令牌范围为“write”或“read write”,则您可以充分利用作业模板作为其管理员。

要获取和使用令牌,首先创建一个应用程序令牌

  1. 创建一个应用程序,并将 authorization_grant_type 设置为 password。将以下内容 HTTP POST 到 /api/v2/applications/ 端点(提供您自己的组织 ID)

{
    "name": "Admin Internal Application",
    "description": "For use by secure services & clients. ",
    "client_type": "confidential",
    "redirect_uris": "",
    "authorization_grant_type": "password",
    "skip_authorization": false,
    "organization": <organization-id>
}
  1. 创建一个令牌并将其 POST 到 /api/v2/tokens/ 端点。

{
    "description": "My Access Token",
    "application": <application-id>,
    "scope": "write"
}

这将返回一个 <token-value>,您可以使用它来验证将来 的请求(此值不会再次显示)。

  1. 使用令牌访问资源。以下使用 curl 作为示例。

curl -H "Authorization: Bearer <token-value>" -H "Content-Type: application/json" https://<awx>/api/v2/users/

如果您尚未设置 CA 并使用 SSL,则可能需要 -k 标志。

要撤销令牌,您可以对该令牌的详细信息页面执行 DELETE 操作, 使用该令牌的 ID。例如:

curl -u <user>:<password> -X DELETE https://<awx>/api/v2/tokens/<pk>/

同样,使用令牌:

curl -H "Authorization: Bearer <token-value>" -X DELETE https://<awx>/api/v2/tokens/<pk>/

19.3. 应用程序功能

此页面列出了用于授权、令牌刷新和撤销的 OAuth 2 工具 端点。 /api/o/ 端点不适用于浏览器,并且不支持 HTTP GET。 此处规定的端点严格遵循 OAuth 2 的 RFC 规范,因此请使用它作为详 细参考。以下是 AWX 中这些端点的典型使用示例,尤其是创建 使用各种授权类型的应用程序时。

  • 授权码

  • 密码

注意

您可以使用 AWX 用户界面执行此处描述的任何应用程序功 能。有关详细信息,请参阅 *AWX 用户指南* 中的 应用程序 部分。

19.3.1. 使用 authorization code 授权类型的应用程序

当需要直接向外部应用程序或服务颁发访问令牌时,应使用 应用程序 authorization code 授权类型。

注意

您只能在使用应用程序时使用 authorization code 类型来获取访问令牌。当将外部 web 应用程序与 AWX 集成时,该 web 应用程序可能需要代表其他 web 应用程序中的用户创建 OAuth2 令牌。在 AWX 中使用 authorization code 授权类型创建应用程序是首选方法,因为:

  • 这允许外部应用程序使用用户的凭据从 AWX 获取用户的令牌。

  • 为特定应用程序颁发的隔离令牌允许轻松管理这些令牌(例如,撤销 与该应用程序关联的所有令牌,而不必撤销系统中的 *所有* 令牌)。

要使用 authorization-code 授权类型创建名为 *AuthCodeApp* 的应用程序,请对 /api/v2/applications/ 端点执行 POST 操作。

{
    "name": "AuthCodeApp",
    "user": 1,
    "client_type": "confidential",
    "redirect_uris": "http://<awx>/api/v2",
    "authorization_grant_type": "authorization-code",
    "skip_authorization": false
}


.. _`Django-oauth-toolkit simple test application`: http://django-oauth-toolkit.herokuapp.com/consumer/

当您从客户端应用程序使用 response_typeclient_idredirect_urisscopeauthorize 端点执行 GET 操作时,将发生的流程。

  1. AWX 会将授权码和状态响应到应用程序中指定的 redirect_uri

  2. 然后,客户端应用程序使用 codeclient_idclient_secretgrant_typeredirect_uri 对 AWX 上的 api/o/token/ 端点执行 POST 操作。

  3. AWX 将响应 access_tokentoken_typerefresh_tokenexpires_in

请参阅 Django 的测试您的授权服务器 工具包以测试此流程。

您可以在 **系统设置** 屏幕中指定授权码保持有效的秒数。

../_images/configure-awx-system-misc-sys-authcode-expire.png

在此持续时间后请求访问令牌将失败。根据 RFC6749 建议,持续时间默认为 600 秒(10 分钟)。

使用授权码授权类型设置与 AWX 的应用程序集成的最佳方法 是将这些跨站点请求的来源列入白名单。更一般地说,您需要将 您与 AWX 集成的服务或应用程序列入白名单,并希望为其提供访 问令牌。为此,请让您的管理员将此白名单添加到其本地 AWX 设置中:

CORS_ALLOWED_ORIGIN_REGEXES = [
    r"http://django-oauth-toolkit.herokuapp.com*",
    r"http://www.example.com*"
]

其中 http://django-oauth-toolkit.herokuapp.comhttp://www.example.com 是需要令牌才能访问 AWX 的应用程序。

19.3.2. 使用 password 授权类型的应用程序

password 授权类型或 Resource owner password-based 授权类型非常适合对 web 应用程序具有本机访问权限的用户, 并且应在客户端为资源所有者时使用。以下假设一个名为“默认 应用程序”的应用程序,其授权类型为 password

{
    "id": 6,
    "type": "application",
    ...
    "name": "Default Application",
    "user": 1,
    "client_id": "gwSPoasWSdNkMDtBN3Hu2WYQpPWCO9SwUEsKK22l",
    "client_secret": "fI6ZpfocHYBGfm1tP92r0yIgCyfRdDQt0Tos9L8a4fNsJjQQMwp9569eIaUBsaVDgt2eiwOGe0bg5m5vCSstClZmtdy359RVx2rQK5YlIWyPlrolpt2LEpVeKXWaiybo",
    "client_type": "confidential",
    "redirect_uris": "",
    "authorization_grant_type": "password",
    "skip_authorization": false
}

对于 password 授权类型,不需要登录,因此您可以简单地使用 curl 通过 /api/v2/tokens/ 端点获取个人访问令牌。

curl --user <user>:<password> -H "Content-type: application/json" \
--data '{
    "description": "Token for Nagios Monitoring app",
    "application": 1,
    "scope": "write"
}' \
https://<awx>/api/v2/tokens/

注意

特殊的 OAuth 2 端点仅支持使用 x-www-form-urlencoded **Content-type**,因此, api/o/* 端点都不接受 application/json

成功后,将以 JSON 格式显示响应,其中包含访问令牌、刷新令牌 和其他信息。

HTTP/1.1 200 OK
Server: nginx/1.12.2
Date: Tue, 05 Dec 2017 16:48:09 GMT
Content-Type: application/json
Content-Length: 163
Connection: keep-alive
Content-Language: en
Vary: Accept-Language, Cookie
Pragma: no-cache
Cache-Control: no-store
Strict-Transport-Security: max-age=15768000

{"access_token": "9epHOqHhnXUcgYK8QanOmUQPSgX92g", "token_type": "Bearer", "expires_in": 315360000000, "refresh_token": "jMRX6QvzOTf046KHee3TU5mT3nyXsz", "scope": "read"}

19.4. 应用程序令牌功能

本节描述与令牌相关的刷新和撤销功能。以下所有内容(在 /api/o/ 端点刷新和撤销令牌)当前只能使用应用程序令牌完成。

19.4.1. 刷新现有的访问令牌

以下示例显示了具有提供刷新令牌的现有访问令牌。

{
    "id": 35,
    "type": "access_token",
    ...
    "user": 1,
    "token": "omMFLk7UKpB36WN2Qma9H3gbwEBSOc",
    "refresh_token": "AL0NK9TTpv0qp54dGbC4VUZtsZ9r8z",
    "application": 6,
    "expires": "2017-12-06T03:46:17.087022Z",
    "scope": "read write"
}

/api/o/token/ 端点用于刷新访问令牌。

curl \
    -d "grant_type=refresh_token&refresh_token=AL0NK9TTpv0qp54dGbC4VUZtsZ9r8z" \
    -u "gwSPoasWSdNkMDtBN3Hu2WYQpPWCO9SwUEsKK22l:fI6ZpfocHYBGfm1tP92r0yIgCyfRdDQt0Tos9L8a4fNsJjQQMwp9569eIaUBsaVDgt2eiwOGe0bg5m5vCSstClZmtdy359RVx2rQK5YlIWyPlrolpt2LEpVeKXWaiybo" \
    http://<awx>/api/o/token/ -i

在上述 POST 请求中,refresh_token 由上面的访问令牌的 refresh_token 字段提供。身份验证信息格式为 <client_id>:<client_secret>,其中 client_idclient_secret 是访问令牌相关联的底层应用程序 的相应字段。

注意

特殊的 OAuth 2 端点仅支持使用 x-www-form-urlencoded **Content-type**,因此, api/o/* 端点都不接受 application/json

成功后,将以 JSON 格式显示响应,其中包含与之前令牌具有 相同范围信息的新的(刷新的)访问令牌。

HTTP/1.1 200 OK
Server: nginx/1.12.2
Date: Tue, 05 Dec 2017 17:54:06 GMT
Content-Type: application/json
Content-Length: 169
Connection: keep-alive
Content-Language: en
Vary: Accept-Language, Cookie
Pragma: no-cache
Cache-Control: no-store
Strict-Transport-Security: max-age=15768000

{"access_token": "NDInWxGJI4iZgqpsreujjbvzCfJqgR", "token_type": "Bearer", "expires_in": 315360000000, "refresh_token": "DqOrmz8bx3srlHkZNKmDpqA86bnQkT", "scope": "read write"}

本质上,刷新操作通过删除原始令牌来替换现有令牌,然后立即 创建一个与原始令牌具有相同范围和相关应用程序的新令牌。验证 新令牌是否存在以及旧令牌是否已从 /api/v2/tokens/ 端点中删除。

19.4.2. 撤销访问令牌

同样,您可以使用 /api/o/revoke-token/ 端点撤销访问令牌。

通过这种方法撤销访问令牌与删除令牌资源对象相同,但它允许您 通过提供其令牌值和关联的 client_id(以及如果应用程序为 confidential,则提供 client_secret)来删除令牌。例如:

curl -d "token=rQONsve372fQwuc2pn76k3IHDCYpi7" \
-u "gwSPoasWSdNkMDtBN3Hu2WYQpPWCO9SwUEsKK22l:fI6ZpfocHYBGfm1tP92r0yIgCyfRdDQt0Tos9L8a4fNsJjQQMwp9569eIaUBsaVDgt2eiwOGe0bg5m5vCSstClZmtdy359RVx2rQK5YlIWyPlrolpt2LEpVeKXWaiybo" \
http://<awx>/api/o/revoke_token/ -i

注意

特殊的 OAuth 2 端点仅支持使用 x-www-form-urlencoded **Content-type**,因此, api/o/* 端点都不接受 application/json

注意

默认情况下,**允许外部用户创建 OAuth2 令牌**(API 中的 ALLOW_OAUTH2_FOR_EXTERNAL_USERS)设置处于禁用状态。外部用户是指 使用诸如 LDAP 之类的服务或任何其他 SSO 服务在外部进行身份验证 的用户。此设置确保外部用户无法 *创建* 自己的令牌。如果您启用它, 然后禁用它,在此期间由外部用户创建的任何令牌仍然存在,并且不 会自动撤销。

或者,您可以使用 manage 实用程序 revoke_oauth2_tokens 来撤销令牌,如 令牌和会话管理 部分所述。

可以在 AWX 用户界面中的系统级别配置此设置。

../_images/configure-awx-system-oauth2-tokens-toggle.png

成功后,将显示 200 OK 的响应。通过检查令牌是否存在于 /api/v2/tokens/ 端点中来验证删除。