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