自定义 User Provider

未匹配的标注

用户辅助器用于查找用户以进行身份验证。 auth 模块附带一个 数据库辅助器 和一个 [Lucid 辅助器](github. com/adonisjs/auth/blob/develop/src/UserProviders/Lucid/index.ts)使用 Lucid ORM 从 SQL 数据库中查找用户。

如果你想从不同的数据源查找用户,还可以扩展 Auth 模块并添加自定义用户提供程序。在本指南中,我们将完成添加自定义用户提供程序的过程。

注意:这是一个示例项目 使用 mongoose 从 MongoDB 数据库中查找用户。你可以将其用作创建自己的辅助器的灵感。

由外向内扩展

任何时候你都在扩展框架的核心。最好假设您无权访问应用程序代码及其依赖项。换句话说,像编写第三方包一样编写扩展,并使用依赖注入来依赖其他依赖。

让我们首先创建一个用户辅助器,该提供程序依赖于 MongoDB 客户端从数据库中查找用户。 以下示例使用 MongoDB 查询的虚拟代码,你必须将它们替换为自己的实现

mkdir providers/MongoDbAuthProvider
touch providers/MongoDbAuthProvider/index.ts

目录结构如下所示。

providers
└── MongoDbAuthProvider
    └── index.ts

打开新创建的 MongoDbAuthProvider/index.ts 文件并将以下代码粘贴到其中。

// 文件名: providers/MongoDbAuthProvider/index.ts
import type { HashContract } from '@ioc:Adonis/Core/Hash'
import type {
    UserProviderContract,
    ProviderUserContract
} from '@ioc:Adonis/Addons/Auth'

/**
 * “MongoDbAuthProvider”返回的用户对象的样式类
 * 随意改为你想要的属性
 */
export type User = {
  id: string
  email: string
  password: string
  rememberMeToken: string | null
}

/**
 * MongoDbAuthProvider 接受的配置形式。
 * 它需要至少一个驱动属性
 */
export type MongoDbAuthProviderConfig = {
  driver: 'mongo'
}

/**
 * 提供者用户充当你的用户辅助器和
 * AdonisJS 身份验证模块。
 */
class ProviderUser implements ProviderUserContract<User> {
  constructor(public user: User | null, private hash: HashContract) {}

  public getId() {
    return this.user ? this.user.id : null
  }

  public getRememberMeToken() {
    return this.user ? this.user.rememberMeToken : null
  }

  public setRememberMeToken(token: string) {
    if (!this.user) {
      return
    }
    this.user.rememberMeToken = token
  }

  public async verifyPassword(plainPassword: string) {
    if (!this.user) {
      throw new Error('Cannot verify password for non-existing user')
    }

    return this.hash.verify(this.user.password, plainPassword)
  }
}

/**
 * 用户辅助器实现来通过不同的操作查找用户
 */
export class MongoDbAuthProvider implements UserProviderContract<User> {
  constructor(
    public config: MongoDbAuthProviderConfig,
    private hash: HashContract
  ) {}

  public async getUserFor(user: User | null) {
    return new ProviderUser(user, this.hash)
  }

  public async updateRememberMeToken(user: ProviderUser) {
    await mongoDbClient.updateOne(
      { _id: user.getId() },
      { rememberMeToken: user.getRememberMeToken() }
    )
  }

  public async findById(id: string | number) {
    const user = await mongoDbClient.findById(id)
    return this.getUserFor(user || null)
  }

  public async findByUid(uidValue: string) {
    const user = await mongoDbClient.findOne().where('email').equals(uidValue)
    return this.getUserFor(user || null)
  }

  public async findByRememberMeToken(userId: string | number, token: string) {
    const user = await mongoDbClient
      .findOne()
      .where('_id').equals(userId)
      .where('rememberMeToken').equals(token)

    return this.getUserFor(user || null)
  }
}

因为有很多代码,所以让我们分解它并了解每个类及其方法的用途。

用户类型

export type User 块定义你的辅助器将返回的用户的样子。如果你使用的是 ORM,则可以从某个模型推断用户类型,但主要目标是拥有用户的预定义表示。

export type User = {
  id: string
  email: string
  password: string
  rememberMeToken: string | null
}

MongoDb 辅助器配置

MongoDbAuthProviderConfig 类型定义了你的辅助器接受的配置的样式。它必须至少具有 driver 属性,以反映你要向 auth 模块注册的驱动程序名称。

export type MongoDbAuthProviderConfig = {
  driver: 'mongo'
}

ProviderUser 类

ProviderUser 类是你的 UserProvider 和 AdonisJS 身份验证模块之间的桥梁。 auth 模块不知道你从数据源获取的用户对象上存在的属性,因此它需要一些方法来查找 id 或*验证用户密码**。

这就是 ProviderUser 类的作用。它必须实现 ProviderUserContract 接口。

我们还接受 hash 模块作为构造函数参数,以使用 AdonisJS 哈希模块 验证用户密码。

class ProviderUser implements ProviderUserContract<User> {
  constructor(public user: User | null, private hash: HashContract) {}

  public getId() {
    return this.user ? this.user.id : null
  }

  public getRememberMeToken() {
    return this.user ? this.user.rememberMeToken : null
  }

  public setRememberMeToken(token: string) {
    if (!this.user) {
      return
    }
    this.user.rememberMeToken = token
  }

  public async verifyPassword(plainPassword: string) {
    if (!this.user) {
      throw new Error('Cannot verify password for non-existing user')
    }

    return this.hash.verify(this.user.password, plainPassword)
  }
}

getId

返回唯一标识用户的属性的值。


getRememberMeToken

返回记住密码标记的值。当没有生成记住密码的令牌时,它必须是字符串或 null


setRememberMeToken

获取用户对象上的记住密码令牌属性。请注意,你不用在此方法中保留记住密码的令牌,只需更新属性。

令牌由 UserProvider 类上的 updateRememberMeToken 持久化。


验证密码

验证用户密码。此方法从 auth 模块接收纯文本密码,如果密码匹配,则必须返回 true,如果密码不正确,则必须返回 false


UserProvider 类

UserProvider 类用于查找用户或为给定用户保留记住密码的令牌。这是你稍后将在 AdonisJS auth 模块中注册的类。

UserProvider 必须实现 UserProviderContract 接口。

export class MongoDbAuthProvider implements UserProviderContract<User> {
  constructor(
    public config: MongoDbAuthProviderConfig,
    private hash: HashContract
  ) {}

  public async getUserFor(user: User | null) {
    return new ProviderUser(user, this.hash)
  }

  public async updateRememberMeToken(user: ProviderUser) {
    await mongoDbClient.updateOne(
      { _id: user.getId() },
      { rememberMeToken: user.getRememberMeToken() }
    )
  }

  public async findById(id: string | number) {
    const user = await mongoDbClient.findById(id)
    return this.getUserFor(user || null)
  }

  public async findByUid(uidValue: string) {
    const user = await mongoDbClient.findOne().where('email').equals(uidValue)
    return this.getUserFor(user || null)
  }

  public async findByRememberMeToken(userId: string | number, token: string) {
    const user = await mongoDbClient
      .findOne()
      .where('_id').equals(userId)
      .where('rememberMeToken').equals(token)

    return this.getUserFor(user || null)
  }
}

getUserFor

返回你从数据源查找的用户对象的 ProviderUser 实例。


updateRememberMeToken

使用新的记住密码令牌更新数据源。此方法接收具有更新 rememberMeToken 属性的 ProviderUser 类的实例。


findById

通过用户的唯一 ID 查找用户。此方法必须返回 ProviderUser 类的实例。


findByUid

通过使用他们的电子邮件地址或用户名或适用于你的数据源的任何其他属性来查找用户进行登录。

例如,Lucid 辅助器 依赖配置 通过 uid 查找用户.

此方法必须返回 ProviderUser 类的实例。


findByRememberMeToken

下一步是向 auth 模块注册用户辅助器。你必须在辅助器的 boot 方法中执行此操作。对于此示例,我们将使用 providers/AppProvider.ts 文件。
此方法必须返回 ProviderUser 类的实例。

注册用户辅助器

下一步是向 auth 模块注册用户提供程序。你必须在辅助器的boot方法中执行此操作。对于此示例,我们将使用providers/AppProvider.ts文件。

// 文件名:providers/AppProvider.ts
import { ApplicationContract } from '@ioc:Adonis/Core/Application'

export default class AppProvider {
  constructor(protected app: ApplicationContract) {}

  public async boot() {
    const Auth = this.app.container.resolveBinding('Adonis/Addons/Auth')
    const Hash = this.app.container.resolveBinding('Adonis/Core/Hash')

    const { MongoDbAuthProvider } = await import('./MongoDbAuthProvider')

    Auth.extend('provider', 'mongo', (_, __, config) => {
      return new MongoDbAuthProvider(config, Hash)
    })
  }
}

Auth.extend 方法总共接受三个参数。

  • 扩展的类型。添加用户辅助器时,应始终将其设置为 provider
  • 辅助器的名称
  • 最后,返回用户辅助器实例的回调。回调方法接收 config 作为第三个参数。

更新类型和配置

在开始使用 mongo 辅助器之前,你必须在合约文件中定义它并定义它的配置。

打开 contracts/auth.ts 文件并在其中附加以下代码片段。

// 文件名: contracts/auth.ts
import type {
  MongoDbAuthProvider,
  MongoDbAuthProviderConfig,
} from '../providers/MongoDbAuthProvider'

declare module '@ioc:Adonis/Addons/Auth' {
  interface ProvidersList {
    user: {
      implementation: MongoDbAuthProvider
      config: MongoDbAuthProviderConfig
    }
  }

  interface GuardsList {
    web: {
      implementation: SessionGuardContract<'user', 'web'>
      config: SessionGuardConfig<'user'>
    }
  }
}

最后,让我们更新 config/auth.ts 文件并为用户辅助器定义配置。

// 文件名: config/auth.ts
const authConfig: AuthConfig = {
  guard: 'web',
  guards: {
    web: {
      driver: 'session',

      provider: {
        driver: 'mongo'
      }
    }
  }
}

本文章首发在 LearnKu.com 网站上。

本译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。

原文地址:https://learnku.com/docs/adonisjs/5.x/au...

译文地址:https://learnku.com/docs/adonisjs/5.x/au...

上一篇 下一篇
贡献者:1
讨论数量: 0
发起讨论 只看当前版本


暂无话题~