Basic Auth 守卫

本指南介绍如何使用 HTTP Basic 身份验证协议对 HTTP 请求进行身份验证。你将学习:

  • basic 身份验证的工作原理以及何时使用它
  • 如何配置 basic auth 守卫和用户提供者
  • 如何使用 basic auth 对请求进行身份验证
  • 如何使用 auth 中间件保护路由

概述

Basic auth 守卫实现了 HTTP 身份验证框架 。客户端在每个请求的 Authorization 头中以 base64 编码字符串的形式发送凭据。例如,Authorization: Basic am9obkBleGFtcGxlLmNvbTpzZWNyZXQ= 包含了用户的邮箱和密码。

Basic 身份验证是无状态的,因为服务器不维护任何持久化的 session,也不签发令牌。相反,客户端必须在每个请求中都包含凭据。由于凭据是明文发送的(仅做了 base64 编码),在生产环境中 basic 身份验证必须始终通过 HTTPS 使用。

虽然 basic 身份验证设置简单,但由于缺乏 MFA 或账户管理等现代安全特性,不推荐用于生产应用。它主要用于早期开发阶段或简单的内部工具。

配置守卫

首先,在你的 config/auth.ts 文件中定义 basic auth 守卫。你必须从 @adonisjs/auth/basic_auth 模块导入 basicAuthGuardbasicAuthUserProvider

config/auth.ts
import { defineConfig } from '@adonisjs/auth'
import { basicAuthGuard, basicAuthUserProvider } from '@adonisjs/auth/basic_auth'

const authConfig = defineConfig({
  default: 'basic',
  guards: {
    basic: basicAuthGuard({
      provider: basicAuthUserProvider({
        model: () => import('#models/user'),
      }),
    }),
  },
})

export default authConfig

basicAuthUserProvider 使用你的 User 模型来查找和验证凭据。它期望该模型拥有一个 verifyCredentials 静态方法,该方法通常由 AuthFinder mixin 提供。

配置 User 模型

basicAuthUserProvider 可与任何代表你用户实体的 Lucid 模型配合使用。在安装过程中,add 命令会生成一个应用了 withAuthFinder mixin 的 User 模型。

app/models/user.ts
import { DateTime } from 'luxon'
import { compose } from '@adonisjs/core/helpers'
import { BaseModel, column } from '@adonisjs/lucid/orm'
import hash from '@adonisjs/core/services/hash'
import { withAuthFinder } from '@adonisjs/auth/mixins/lucid'

/**
 * 应用 withAuthFinder mixin 会向你的模型添加
 * verifyCredentials 静态方法。
 */
const AuthFinder = withAuthFinder(() => hash.use('scrypt'), {
  uids: ['email'],
  passwordColumnName: 'password',
})

export default class User extends compose(BaseModel, AuthFinder) {
  @column({ isPrimary: true })
  declare id: number

  @column()
  declare email: string

  @column()
  declare password: string

  @column.dateTime({ autoCreate: true })
  declare createdAt: DateTime

  @column.dateTime({ autoCreate: true, autoUpdate: true })
  declare updatedAt: DateTime
}

对请求进行身份验证

客户端必须包含 Authorization 头,形式为 Basic 一词,后跟一个空格,以及 base64 编码的凭据(通常是 email:password)。

Authorization: Basic am9obkBleGFtcGxlLmNvbTpzZWNyZXQ=

使用 auth 中间件

auth 中间件应用到需要身份验证的路由。该中间件会自动读取头信息,使用配置的提供者验证凭据,并将用户附加到 HTTP 上下文。

start/routes.ts
import { middleware } from '#start/kernel'
import router from '@adonisjs/core/services/router'

router
  .get('/projects', async ({ auth }) => {
    /**
     * 现在 auth.user 属性就是已身份验证的用户。
     * 使用 auth.getUserOrFail() 以避免非空断言。
     */
    const user = auth.getUserOrFail()
    return user.related('projects').query()
  })
  .use(middleware.auth({ guards: ['basic'] }))

如果凭据缺失或无效,中间件会抛出 E_UNAUTHORIZED_ACCESS 异常。

手动身份验证

要在不使用中间件的情况下进行身份验证,可调用 auth.authenticate()auth.authenticateUsing()

start/routes.ts
router.get('/projects', async ({ auth }) => {
  /**
   * 使用默认守卫进行身份验证。
   * 失败时抛出 E_UNAUTHORIZED_ACCESS。
   */
  const user = await auth.authenticate()
  
  return user.related('projects').query()
})
Warning

Basic 身份验证会在 每个 请求上执行一次数据库查询和密码验证。与基于 session 或令牌的身份验证相比,这在计算上开销很大。如果性能是关注点,随着应用规模增长,请考虑迁移到 Session 守卫Access tokens 守卫

下一步