# 认证

> 合作方密钥、二十六个权限范围、一份授权意味着什么，以及如何在不停机的情况下轮换。

Source: https://developers.backresto.com/zh/docs/authentication

每一个合作方 API 请求都携带一份凭据，放在标准的位置：

```http
Authorization: Bearer brp_<prefix>.<secret>
```

没有别的方案。没有放在查询字符串里的密钥，没有 basic auth，没有 cookie。缺少这个
请求头、或者值格式不对的请求，会在其他一切被判断之前就返回 `401`。

## 密钥是什么

一把密钥由一个点分成两半。

| 半段 | 是什么 | 可以出现在哪里 |
| --- | --- | --- |
| `brp_<prefix>` | 这份凭据的公开标识符。 | 你的日志、一封支持邮件、本站上的密钥列表。 |
| `<secret>` | 256 位随机数。 | 你的密钥管理器，以及 `Authorization` 请求头。 |

BackResto 保存前缀和密钥串的带密钥摘要。**密钥串本身不会被保存，也无法找回**：
你找不回，支持人员找不回，从数据库里也找不回。如果它丢了，吊销这把密钥，再造
一把。

## 授权：餐厅 × 权限范围

一把密钥不是「一个带权限的账号」。它是一份明确授权的清单，每一条都是这样一对：

一共有**二十六个权限范围**，它们的构词法值得一次性搞清楚：

| 权限范围 | 授予对什么的访问 |
| --- | --- |
| `<collection>:read` | [那二十六个集合](https://developers.backresto.com/zh/docs/collections)中的一个：`deliveries:read`、`delivery-pictures:read`、`cooling:read`、`temperature-records:read`、`traceability-labels:read` 等等，一个集合一个权限范围。 |

每一个权限范围都以 `:read` 结尾。没有任何一个合作方权限范围可以写入，也造不出一个
来：这个 API 的写入一侧属于 BackResto 应用，而一把合作方密钥在结构上就不可能持有
写入权限。

一把在 `restaurant-1` 和 `restaurant-2` 上被授予 `deliveries:read`、却只在
`restaurant-1` 上被授予 `delivery-pictures:read` 的密钥，能读到第一家餐厅的收货照片，
对第二家则得到 `403`。这是一种受支持的配置，不是配错了。有些集成要的就是记录
而不要图片。

只申请你用得上的。二十六个权限范围不是一份用来逐项打钩的菜单：餐厅会在同意之前读
一遍这份清单，而一份「全都要」的申请，比一份只要你的产品真正会读的那四个集合的
申请，走完流程要久得多。

三种失败模式，有意区分开：

- **`404`**：密钥对那家餐厅根本没有任何授权。API 不会向一个无权的调用方透露某家
  餐厅是否存在。
- **`403`**：密钥对那家餐厅有授权，但没有这个端点需要的权限范围。
- **`401`**：除别的情形之外，也包括一把一份授权都不剩的密钥。一把被剥掉最后一份
  授权的密钥会停止通过认证，而不是返回空结果。

想知道一把密钥究竟持有什么，就去问它：`GET /v1/restaurants` 列出那些餐厅及其权限
范围，而 [`GET /v1/restaurants/{id}/collections`](https://developers.backresto.com/zh/docs/collections) 列出它打开的
那些集合。

## 谁可以签发

我们签发，按申请签发，并且只为已经同意的餐厅签发。要发些什么、会拿到什么，见
[获取密钥](https://developers.backresto.com/zh/docs/access)。

授权在密钥开通时确定，只有通过另一次申请才会更改。没有任何一条路径（无论是给你
的还是给我们的）能在餐厅没有再次同意的情况下扩大一把密钥。

## 过期与吊销

除非你申请的本来就是会过期的密钥，否则密钥不会自行过期。它在被吊销之前一直有效。

吊销立即生效：下一个带着这把密钥的请求返回 `401`，和一把未知或已过期的密钥得到的
答复相同。它无法撤销，也不需要撤销：替代品是一把新密钥，而不是一把被恢复的旧
密钥。

## 不停机轮换

一个集成可以同时持有两把有效密钥，所以轮换不需要维护窗口。请我们做轮换，顺序是
这样的：

1. 我们签发第二把密钥，餐厅和权限范围与原来相同。
2. 你部署新的密钥串，并在它到处都生效之后告诉我们。
3. 我们确认旧密钥已经不再被使用。我们能看到每把密钥最后一次通过认证是什么时候，
   正是这个信号让第 4 步是安全的。
4. 我们吊销旧的那把。

按你自己选的节奏轮换，并在你希望旧密钥消失之前提前几天提出申请：第 2 步和第 3 步
需要你我配合，而上面这个顺序的全部意义，就是任何时候都不会有一段短暂的中断。

## 操作守则

- **到手就存好，然后删掉那封邮件。** 做完这件事之后，密钥串正好只存在于两个地方：
  你的密钥管理器，以及 `Authorization` 请求头。
- **一个部署一把密钥**，而不是一家公司一把。一把泄露的预发布密钥不该变成一次生产
  事故，一次吊销也不该拖垮泄露的那个东西之外的任何东西。
- **绝不要把密钥串发给我们**：不要写进工单，也不要拿它来指认一把密钥。公开前缀就
  能毫不含糊地指明它，而且写在哪里都安全。
- **在你自己的监控里盯住 `401`。** 一把开始失败的密钥是被吊销了，答案是一场对话，
  而不是一个重试循环。
