身份验证
本指南介绍 AdonisJS 身份验证系统。你将学习:
- 守卫(guards)和提供者(providers)如何协同工作来验证用户
- 为你的应用类型选择哪个守卫
- 如何安装和配置 auth 包
- Initialize auth 中间件的作用
概述
AdonisJS 提供了一个健壮的身份验证系统,用于登录和验证不同应用类型中的用户,无论你是在构建服务端渲染应用、供 SPA 使用的 API,还是移动应用的后端。
身份验证包围绕两个核心概念构建:
- 守卫(Guards) 是特定身份验证方法的端到端实现。例如,session 守卫通过 cookie 和会话来验证用户,而 access tokens 守卫则使用 bearer token 来验证请求。
- 提供者(Providers) 负责从你的数据库中查找用户并验证 token。你可以使用内置的 Lucid 提供者,或者针对自定义数据源实现你自己的提供者。
AdonisJS 的安全原语旨在防范常见的漏洞。密码和 token 会被正确地进行哈希处理,并且实现会防范 计时攻击(timing attacks) 和 会话固定攻击(session fixation attacks) 。
auth 包不包含的内容
auth 包专注于验证 HTTP 请求。以下功能不在其范围内:
- 用户注册(表单、邮箱验证、账户激活)
- 账户管理(密码找回、邮箱更新)
- 授权和权限(请改用 Bouncer )
在寻找完整的身份验证系统吗? AdonisJS Kit 提供了全栈组件,带有用于用户注册、邮箱验证、密码找回、个人资料管理等开箱即用的流程。
选择身份验证守卫
AdonisJS 内置了三个守卫。使用下表来确定哪个守卫适合你的应用。
| 应用类型 | 推荐守卫 | 原因 |
|---|---|---|
| 服务端渲染的 Web 应用 | Session | cookie 与浏览器请求天然协作 |
| 同一域名下的 SPA | Session | 在 api.example.com 和 example.com 之间共享 cookie |
| 不同域名下的 SPA | Access tokens | 跨源请求无法共享 cookie |
| 移动应用 | Access tokens | 原生应用无法使用基于 cookie 的会话 |
| 第三方 API 访问 | Access tokens | 客户端需要可存储的长生命周期 token |
| 快速原型开发 | Basic auth | 设置简单,无需数据库表 |
Session 守卫
session 守卫使用 @adonisjs/session 包来跟踪已登录用户。登录成功后,用户的标识符会存储在会话中,并向浏览器发送一个会话 cookie。后续请求会包含这个 cookie,使服务器能够恢复用户的已认证状态。
几十年来,会话和 cookie 一直是 Web 身份验证的标准。当你的客户端可以接受和发送 cookie 时,它们工作得很好,对于服务端渲染应用以及托管在与你的 API 相同顶级域名下的 SPA 来说正是这种情况。
另请参阅: Session 守卫文档
Access tokens 守卫
Access tokens 是在登录后发给用户的加密安全随机字符串。客户端存储该 token,并将其包含在后续请求的 Authorization 请求头中。AdonisJS 使用不透明的 access tokens(而非 JWT),它们以哈希形式存储在你的数据库中以供验证。
当你的客户端无法使用 cookie 时,请使用 access tokens:
- 原生移动应用
- 桌面应用
- 与你的 API 不同域的 Web 应用
- 需要编程式 API 访问的第三方集成
客户端应用负责安全地存储 token。Access tokens 代表用户对你的应用提供无限制的访问权限,因此泄露它们会带来安全风险。
另请参阅: Access tokens 守卫文档
Basic auth 守卫
basic auth 守卫实现了
HTTP 身份验证框架
。客户端在每个请求的 Authorization 请求头中发送 base64 编码的凭据。如果凭据无效,浏览器会显示一个原生的登录提示。
不建议在生产应用中使用基本身份验证,因为凭据会随着每个请求一起发送,并且用户体验仅限于浏览器内置的提示。但是,在开发的早期阶段或内部工具中,它会很有用。
另请参阅: Basic auth 守卫文档
选择用户提供者
用户提供者(user providers)在身份验证期间负责查找用户和验证 token。每种守卫类型对其提供者都有特定要求。
session 守卫提供者通过 ID(存储在会话中)查找用户。access tokens 守卫提供者还会根据数据库中的哈希值验证 token。AdonisJS 为所有内置守卫都提供了基于 Lucid 的提供者,它们使用你的 Lucid 模型来查询数据库。
安装
auth 包已通过 web 和 api 起步套件预先配置好。要将它添加到现有应用中,请基于你偏好的守卫运行以下命令之一:
# Session 守卫(推荐用于 Web 应用)
node ace add @adonisjs/auth --guard=session
# Access tokens 守卫(推荐用于 API)
node ace add @adonisjs/auth --guard=access_tokens
# Basic auth 守卫
node ace add @adonisjs/auth --guard=basic_auth
查看 add 命令执行的步骤
-
使用检测到的包管理器安装
@adonisjs/auth包。 -
在
adonisrc.ts文件中注册以下服务提供者。
{
providers: [
// ...其他 providers
() => import('@adonisjs/auth/auth_provider')
]
}
- 在
start/kernel.ts文件中创建并注册以下中间件。
router.use([
() => import('@adonisjs/auth/initialize_auth_middleware')
])
router.named({
auth: () => import('#middleware/auth_middleware'),
// 仅在使用 session 守卫时注册
guest: () => import('#middleware/guest_middleware')
})
-
在
app/models中创建User模型。 -
为
users表创建数据库迁移。 -
根据所选守卫创建额外的迁移(例如,针对 access tokens 守卫的
auth_access_tokens)。
Initialize auth 中间件
在设置期间,@adonisjs/auth/initialize_auth_middleware 会被添加到你的应用中间件栈中。该中间件在每个请求上运行,并创建
Authenticator
类的实例,将其附加到 ctx.auth。
initialize auth 中间件不会验证请求或保护路由。它唯一的职责是设置 authenticator 实例,使其在请求生命周期内可用。要保护路由,请使用 auth 中间件 。
如果你的应用使用 Edge 模板,authenticator 也可作为 auth 变量使用:
@if(auth.isAuthenticated)
<p>Hello {{ auth.user.email }}</p>
@end
创建 users 表
add 命令会在 database/migrations 中为 users 表创建一个迁移。在运行迁移之前,你可以修改此文件以匹配你的应用需求。
import { BaseSchema } from '@adonisjs/lucid/schema'
export default class extends BaseSchema {
protected tableName = 'users'
async up() {
this.schema.createTable(this.tableName, (table) => {
table.increments('id').notNullable()
table.string('full_name').nullable()
table.string('email', 254).notNullable().unique()
table.string('password').notNullable()
table.timestamp('created_at').notNullable()
table.timestamp('updated_at').nullable()
})
}
async down() {
this.schema.dropTable(this.tableName)
}
}
修改迁移后,更新 app/models/user.ts 中的 User 模型以反映你添加、重命名或删除的任何列。
下一步
安装好 auth 包后,你就可以在应用中实现身份验证了:
- 验证用户凭据 :了解如何在登录期间安全地验证密码
- Session 守卫 :为 Web 应用实现基于 cookie 的身份验证
- Access tokens 守卫 :为 API 和移动应用实现基于 token 的身份验证
- 社交身份验证 :允许用户使用 GitHub、Google 和其他提供商登录