3.6. 身份验证和授权

3.6.1. 服务器管理员

[admins]

在版本 3.0.0 中更改: CouchDB 需要一个管理员帐户才能启动。如果没有创建管理员帐户,CouchDB 将打印错误消息并终止。

CouchDB 服务器管理员和密码不存储在 _users 数据库中,而是存储在 CouchDB 加载其 ini 文件时找到的最后一个 [admins] 部分中。有关配置文件顺序和行为的详细信息,请参阅 :config:intro。此文件(可能是 /opt/couchdb/etc/local.ini/opt/couchdb/etc/local.d/10-admins.ini,当 CouchDB 从软件包安装时)应适当保护,并且只能由系统管理员读取。

[admins]
;admin = mysecretpassword
admin = -hashed-6d3c30241ba0aaa4e16c6ea99224f915687ed8cd,7f4a3e05e0cbc6f48a0035e3508eef90
architect = -pbkdf2-43ecbd256a70a3a2f7de40d2374b6c3002918834,921a12f74df0c1052b3e562a23cd227f,10000

管理员可以直接添加到 [admins] 部分,当 CouchDB 重新启动时,密码将被加盐和加密。您也可以使用 HTTP 接口创建管理员帐户;这样,您无需重新启动 CouchDB,也不需要临时存储或以明文形式传输密码。HTTP /_node/{node-name}/_config/admins 端点支持查询、删除或创建新的管理员帐户。

GET /_node/nonode@nohost/_config/admins HTTP/1.1
Accept: application/json
Host: localhost:5984
HTTP/1.1 200 OK
Cache-Control: must-revalidate
Content-Length: 196
Content-Type: application/json
Date: Fri, 30 Nov 2012 11:37:18 GMT
Server: CouchDB (Erlang/OTP)
{
    "admin": "-hashed-6d3c30241ba0aaa4e16c6ea99224f915687ed8cd,7f4a3e05e0cbc6f48a0035e3508eef90",
    "architect": "-pbkdf2-43ecbd256a70a3a2f7de40d2374b6c3002918834,921a12f74df0c1052b3e562a23cd227f,10000"
}

如果您已经拥有加盐的加密密码字符串(例如,来自旧的 ini 文件或来自不同的 CouchDB 服务器),那么您可以存储“原始”加密字符串,而无需让 CouchDB 对其进行双重加密。

PUT /_node/nonode@nohost/_config/admins/architect?raw=true HTTP/1.1
Accept: application/json
Content-Type: application/json
Content-Length: 89
Host: localhost:5984

"-pbkdf2-43ecbd256a70a3a2f7de40d2374b6c3002918834,921a12f74df0c1052b3e562a23cd227f,10000"
HTTP/1.1 200 OK
Cache-Control: must-revalidate
Content-Length: 89
Content-Type: application/json
Date: Fri, 30 Nov 2012 11:39:18 GMT
Server: CouchDB (Erlang/OTP)

"-pbkdf2-43ecbd256a70a3a2f7de40d2374b6c3002918834,921a12f74df0c1052b3e562a23cd227f,10000"

有关详细信息,请参阅 security,包括配置 PBKDF2 的工作因子,以及 PBKDF2 (RFC-2898) 中的算法本身。

在版本 1.4 中更改: 添加了 PBKDF2 服务器端哈希加盐密码支持,现在作为 _config/admins API 的同步调用。

3.6.2. 身份验证配置

[chttpd]
require_valid_user

在版本 3.2 中更改: 从 [couch_httpd_auth] 部分移至 [chttpd] 部分

当此选项设置为 true 时,不允许匿名用户发出任何请求。每个人都必须经过身份验证。

[chttpd]
require_valid_user = false
require_valid_user_except_for_up

当此选项设置为 true 时,不允许匿名用户发出任何请求,除了 /_up 端点。其他所有人必须经过身份验证。

[chttpd]
require_valid_user_except_for_up = false
[chttpd_auth]

在版本 3.2 中更改: 这些选项已移至 [chttpd_auth] 部分:authentication_redirecttimeoutauth_cache_sizeallow_persistent_cookiesiterationsmin_iterationsmax_iterationssecretusers_db_publicx_auth_rolesx_auth_tokenx_auth_usernamecookie_domainsame_site

allow_persistent_cookies

在版本 3.2 中更改: 从 [couch_httpd_auth] 部分移至 [chttpd_auth] 部分

当设置为 true 时,CouchDB 将在 cookie 上设置 Max-Age 和 Expires 属性,这会导致用户代理(如浏览器)在重启时保留 cookie。

[chttpd_auth]
allow_persistent_cookies = true
cookie_domain

在版本 2.1.1 中新增。

在版本 3.2 中更改: 从 [couch_httpd_auth] 部分移至 [chttpd_auth] 部分

配置 AuthSession cookie 的 domain 属性。默认情况下,domain 属性为空,导致 cookie 设置在 CouchDB 的域上。

[chttpd_auth]
cookie_domain = example.com
same_site

在版本 3.0.0 中新增。

在版本 3.2 中更改: 从 [couch_httpd_auth] 部分移至 [chttpd_auth] 部分

当此选项设置为非空值时,将向 AuthSession cookie 添加 SameSite 属性。有效值为 nonelaxstrict

[chttpd_auth]
same_site = strict
auth_cache_size

在版本 3.2 中更改: 从 [couch_httpd_auth] 部分移至 [chttpd_auth] 部分

在内存中缓存的 用户上下文对象 数量,以减少磁盘查找。

[chttpd_auth]
auth_cache_size = 50
authentication_redirect

在版本 3.2 中更改: 从 [couch_httpd_auth] 部分移至 [chttpd_auth] 部分

指定在成功身份验证后重定向的位置,前提是客户端接受 text/html 响应(通过 Accept 标头)。

[chttpd_auth]
authentication_redirect = /_utils/session.html
hash_algorithms

在版本 3.3 中新增。

注意

在 CouchDB 3.3.1 版本之前,代理身份验证 仅使用哈希算法 sha1 来验证 X-Auth-CouchDB-Token

设置用于 cookie 和代理身份验证的 HMAC 哈希算法。您可以提供一个用逗号分隔的哈希算法列表。新的 cookie 会话或会话更新将使用第一个哈希算法进行计算。列表中的所有值都可以用于解码 cookie 会话和用于 代理身份验证 的令牌 X-Auth-CouchDB-Token

[chttpd_auth]
hash_algorithms = sha256, sha

注意

您可以选择 CouchDB 安装中使用的 Erlang 版本支持的任何哈希算法。常见的可用哈希列表可能是

sha, sha224, sha256, sha384, sha512

要检索支持的哈希算法的完整列表,您可以使用我们的 bin/remsh 脚本,并使用 crypto:supports(hashs). 检索可用哈希算法的完整列表,或者使用 _node/$node/_versions 端点检索哈希。

警告

我们不建议使用以下哈希算法

md4, md5
iterations

在版本 1.3 中新增。

在版本 3.2 中更改: 从 [couch_httpd_auth] 部分移至 [chttpd_auth] 部分

PBKDF2 算法对密码进行哈希处理的迭代次数。次数越多,哈希的持久性越好,但每次需要身份验证的请求的性能成本也会增加。当使用数十万次迭代时,请使用会话 cookie,否则性能损失将非常大。(内部哈希算法是 SHA1,这会影响推荐的迭代次数。)

[chttpd_auth]
iterations = 10000
min_iterations

在版本 1.6 中新增。

在版本 3.2 中更改: 从 [couch_httpd_auth] 部分移至 [chttpd_auth] 部分

PBKDF2 算法对密码进行哈希处理时允许的最小迭代次数。任何迭代次数少于此的用户都将被禁止。

[chttpd_auth]
min_iterations = 100
max_iterations

在版本 1.6 中新增。

在版本 3.2 中更改: 从 [couch_httpd_auth] 部分移至 [chttpd_auth] 部分

PBKDF2 算法对密码进行哈希处理时允许的最大迭代次数。任何迭代次数大于此的用户都将被禁止。

[chttpd_auth]
max_iterations = 100000
password_regexp

在版本 3.2 中新增。

用于检查新密码/更改密码的 正则表达式 列表。设置后,新用户密码必须与列表中的所有正则表达式匹配。

正则表达式可以与原因文本配对:[{"RegExp", "reason text"}, ...]。如果正则表达式不匹配,其原因文本将附加到默认原因 Password does not conform to requirements.

[couch_httpd_auth]
; Password must be 10 chars long and have one or more uppercase and
; lowercase char and one or more numbers.
password_regexp = [{".{10,}", "Min length is 10 chars."}, "[A-Z]+", "[a-z]+", "\\d+"]
proxy_use_secret

在版本 3.2 中更改: 从 [couch_httpd_auth] 部分移至 [chttpd_auth] 部分

当此选项设置为 true 时,chttpd_auth/secret 选项对于 代理身份验证 是必需的。

[chttpd_auth]
proxy_use_secret = false
public_fields

版本 1.4 中新增。

在版本 3.2 中更改: 从 [couch_httpd_auth] 部分移至 [chttpd_auth] 部分

用户文档(在 couchdb/users_db_suffix 中)中可以被任何用户读取的字段名称的逗号分隔列表。如果未设置或未指定,则经过身份验证的用户只能检索自己的文档。

[chttpd_auth]
public_fields = first_name, last_name, contacts, url

注意

使用 public_fields 允许列表的用户文档属性需要将 chttpd_auth/users_db_public 选项设置为 true(后者选项没有其他用途)。

[chttpd_auth]
users_db_public = true
secret

在版本 3.2 中更改: 从 [couch_httpd_auth] 部分移至 [chttpd_auth] 部分

秘密令牌用于 代理身份验证Cookie 身份验证

[chttpd_auth]
secret = 92de07df7e7a3fe14808cef90a7cc0d91
timeout

在版本 3.2 中更改: 从 [couch_httpd_auth] 部分移至 [chttpd_auth] 部分

自上次请求以来的秒数,在此之后会话将过期。

[chttpd_auth]
timeout = 600
users_db_public

版本 1.4 中新增。

在版本 3.2 中更改: 从 [couch_httpd_auth] 部分移至 [chttpd_auth] 部分

允许所有用户查看用户文档。默认情况下,只有管理员可以浏览所有用户文档,而用户只能浏览自己的文档。

[chttpd_auth]
users_db_public = false
x_auth_roles

在版本 3.2 中更改: 从 [couch_httpd_auth] 部分移至 [chttpd_auth] 部分

包含用户角色列表的 HTTP 标头名称(默认情况下为 X-Auth-CouchDB-Roles),以逗号分隔。用于 代理身份验证

[chttpd_auth]
x_auth_roles = X-Auth-CouchDB-Roles
x_auth_token

在版本 3.2 中更改: 从 [couch_httpd_auth] 部分移至 [chttpd_auth] 部分

包含用于验证授权的令牌的 HTTP 标头名称(默认情况下为 X-Auth-CouchDB-Token)。此令牌是根据 chttpd_auth/secretchttpd_auth/x_auth_username 创建的 HMAC-SHA1。密钥应该在客户端和 CouchDB 节点上相同。如果 chttpd_auth/proxy_use_secret 选项的值不是 true,则此令牌是可选的。用于 代理身份验证

[chttpd_auth]
x_auth_token = X-Auth-CouchDB-Token
x_auth_username

在版本 3.2 中更改: 从 [couch_httpd_auth] 部分移至 [chttpd_auth] 部分

包含用户名(默认情况下为 X-Auth-CouchDB-UserName)的 HTTP 标头名称。用于 代理身份验证

[chttpd_auth]
x_auth_username = X-Auth-CouchDB-UserName
[jwt_auth]
required_claims

此参数是必须存在于任何呈现的 JWT 令牌中的其他强制性 JWT 声明的逗号分隔列表。如果缺少任何声明,则会发送 404 Not Found

[jwt_auth]
    required_claims = exp,iat
roles_claim_name

警告

roles_claim_name 在 CouchDB 3.3 中已弃用,将在以后删除。请迁移到 roles_claim_path

如果存在,作为字符串的 JSON 数组,只要 JWT 令牌有效,它将用作 CouchDB 用户的角色列表。 roles_claim_name 的默认值为 _couchdb.roles

注意

roles_claim_name 的值只能是 JWT 令牌中的顶级属性。如果设置了 roles_claim_path,则忽略 roles_claim_name

假设我们有以下配置

[jwt_auth]
roles_claim_name = my-couchdb.roles

CouchDB 将在 JWT 令牌中搜索属性 my-couchdb.roles

{
    "my-couchdb.roles": [
        "role_1",
        "role_2"
    ]
}
roles_claim_path

在版本 3.3 中新增。

引入此参数是为了克服 roles_claim_name 的缺点,因为使用 roles_claim_name 无法映射 JWT 令牌中的嵌套角色属性。

注意

如果设置了 roles_claim_path,则忽略 roles_claim_name

现在可以从 JWT 令牌中读取嵌套角色声明到 CouchDB 中。与往常一样,在开始运行之前有一些理论。现在不要害怕,它真的很短很简单。真的!

只有两个字符具有特殊含义。它们是

  • . 用于嵌套 json 属性,以及

  • \. 用于跳过嵌套

就是这样。真的。

假设 JWT 令牌中存在以下数据有效负载

{
    "resource_access": {
        "security.settings": {
            "account": {
                "roles": [
                    "manage-account",
                    "view-profile"
                ]
            }
        }
    }
}

现在,让我们为这个示例定义配置变量 roles_claim_path。它应该看起来像这样

roles_claim_path = resource_access.security\.settings.account.roles

如果属性的键中包含 .,例如 security.settings,则必须在配置参数中使用 \. 对其进行转义。如果使用 .,则它将被解释为嵌套子键。让我们用第二个示例来说明这种行为。 roles_claim_name 有以下配置参数(顺便说一下,如果你没有配置它,它就是默认值)

roles_claim_name = _couchdb.roles

注意

CouchDB 不会为 roles_claim_path 设置任何默认值或隐式值。

要从 roles_claim_name 迁移到 roles_claim_path,你需要更改参数名称并转义 . 以防止 CouchDB 将其解释为嵌套 JSON 键。

roles_claim_path = _couchdb\.roles

假设你的 JWT 令牌对于你的 couchdb 角色声明具有以下数据有效负载

{
    "_couchdb.roles": [
        "accounting-role",
        "view-role"
    ]
}

如果你一切操作正确,来自 _session 端点的响应应该看起来像这样

GET /_session HTTP/1.1
Host: localhost:5984
Authorization: Bearer <JWT token>
HTTP/1.1 200 OK
Content-Type: application/json
{
    "ok": true,
    "userCtx": {
        "name": "1234567890",
        "roles": [
            "accounting-role",
            "view-role"
        ]
    },
    "info": {
    "authentication_handlers": [
        "jwt",
        "proxy",
        "cookie",
        "default"
    ],
    "authenticated": "jwt"
    }
}

就是这样,你完成了从 roles_claim_nameroles_claim_path 的迁移。很简单,不是吗?