> For the complete documentation index, see [llms.txt](https://www.axisnow.io/zh/docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://www.axisnow.io/zh/docs/edge/policies/authn-authz/how-it-works.md).

# 工作原理

认证与授权的评估顺序与 JWT 校验细节以及失败响应

## 评估顺序 <a href="#flow" id="flow"></a>

1. 按规则条件取第一条命中的规则。命中**跳过认证**，或没有规则命中，请求不做认证，继续处理。
2. 命中**强制认证**：用规则引用的认证方式校验凭据。未携带凭据或凭据无效，返回 401 Unauthorized，请求结束。
3. JWT 认证通过后评估授权规则：自上而下取第一条条件成立的规则，按它的允许或拒绝决定，都不成立按**默认动作**。拒绝返回 403 Forbidden，请求结束。自定义认证没有这一步。
4. 允许的请求继续处理，[附加控制](#controls)在这时生效。

<figure><img src="https://3062891322-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FKDgGNU6JXG7cqYCk2aCz%2Fuploads%2Fgit-blob-3f71c7ae215586673a838632a95e43e2659439ce%2Fimage%20(311).png?alt=media" alt="命中强制认证的请求先认证，失败返回 401 Unauthorized；通过后按序评估授权规则，命中即止，无命中按规则里设定的默认动作，拒绝返回 403 Forbidden；跳过认证和没有规则命中的请求不做认证"><figcaption></figcaption></figure>

`OPTIONS` 预检请求不做认证直接放行，浏览器跨域调用不需要为预检单独配规则。规则引用的认证方式不存在、规则条件无法求值时请求放行而不是拒绝，日志里的 `outcome` 为 `config_error`。

## 认证方式 <a href="#methods" id="methods"></a>

认证方式在策略下单独定义，一个认证方式可被多条规则引用。

### JWT <a href="#jwt" id="jwt"></a>

* **取令牌**：配置了多个位置或名称时取到的令牌逐个校验，任一通过即通过。请求头为 `Authorization` 时值必须以 `Bearer` 开头（不区分大小写），缺前缀按未携带凭据处理；其它请求头取原值。请求体位置只读取 JSON 和表单编码的请求体，且不超过 10 KB。
* **验签**：令牌头部的 `alg` 必须与认证方式配置的算法一致，不一致直接拒绝，不接受降级。填写多段公钥时逐个尝试。JWKS 和 OIDC 元数据按地址缓存 5 分钟，到期重新拉取，拉取失败时继续使用缓存的结果并每 10 秒重试；令牌带 `kid` 时在 JWKS 里按 `kid` 找键，不带 `kid` 时 JWKS 里同类型的键必须只有一个。
* **校验声明**：`exp` 不是必需的声明；`iss`、`aud` 等声明不在认证阶段校验，用授权规则限定。
* **JWE**：先解密再验签，令牌头部的 `alg`、`enc` 必须与配置一致，`cty` 必须为 `JWT`；多个密钥按 `kid` 选择，令牌不带 `kid` 时用第一个。

### 自定义 <a href="#custom" id="custom"></a>

执行您写的 `handle(ctx)`，函数的写法、返回值和出错时的处理见[边缘运行时](/zh/docs/edge/policies/edge-runtime.md)。

## 授权规则 <a href="#authz" id="authz"></a>

只有 JWT 认证方式有授权规则，自定义函数不输出身份属性。条件写在令牌的声明上，例如 `aud` 在某几个值之中；数组声明按元素匹配，对象声明按 JSON 字符串匹配。条件写错的规则跳过不参与判定。

## 失败响应 <a href="#responses" id="responses"></a>

认证失败返回 401 Unauthorized，授权拒绝返回 403 Forbidden，响应体为纯文本 `Unauthorized`、`Forbidden`。

## 附加控制 <a href="#controls" id="controls"></a>

* **绕过通用访问控制 / 绕过速率控制**：认证通过的请求不再进入所选插件，两项默认开启。
* **认证失败封禁**：同一规则下同一客户端 IP 在窗口内凭据无效的次数达到上限即封禁该 IP。只计携带了凭据而校验不通过的请求；未携带凭据、授权拒绝、JWKS 拉取失败、认证方式配置错误、自定义函数出错都不计。自定义认证的函数返回 `verified = false` 一律按凭据无效计数，插件无法区分它是未携带还是校验不通过。封禁与通用访问控制的 [IP 封禁](/zh/docs/edge/policies/access-control/how-it-works.md#ban-details)是同一套机制，生效范围和限制见该节。

## 日志字段 <a href="#log-fields" id="log-fields"></a>

每条经过本插件的请求在访问日志的 `extras.authn_authz` 下记录结果，排查先看 `outcome`：

<table data-search="false"><thead><tr><th width="180">字段</th><th>取值</th></tr></thead><tbody><tr><td><code>outcome</code></td><td><code>allowed</code> 通过；<code>unauthenticated</code> 认证失败；<code>unauthorized</code> 授权拒绝；<code>bypass</code> 命中跳过认证；<code>skip</code> 预检请求未认证；<code>config_error</code> 配置错误放行</td></tr><tr><td><code>reason</code></td><td>认证失败的原因：<code>no_credential</code> 未携带凭据；<code>invalid_credential</code> 凭据无效；<code>dependency</code> JWKS 拉取失败；<code>config</code> 认证方式配置错误；<code>runtime</code> 自定义函数出错</td></tr><tr><td><code>message</code></td><td>失败的具体说明，自定义函数通过 <code>auth.result</code> 的 <code>message</code> 给出的文本优先</td></tr><tr><td><code>method</code></td><td><code>jwt-auth</code> 或 <code>custom-auth</code></td></tr><tr><td><code>decision</code>、<code>authz_rule_uuid</code></td><td>授权结果和决定它的规则，<code>default</code> 为按默认动作，<code>empty</code> 为没有授权规则</td></tr><tr><td><code>banned</code></td><td>这次失败触发了封禁</td></tr><tr><td><code>time_us</code>、<code>code_time_us</code></td><td>本插件的耗时和其中自定义函数的耗时，微秒</td></tr></tbody></table>


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://www.axisnow.io/zh/docs/edge/policies/authn-authz/how-it-works.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
