本指南添加 change-password 功能。
change-password 功能让已登录用户通过提供当前密码和新密码来更新密码。
- 已完成添加 magic link的项目
添加 change password 功能
Section titled “添加 change password 功能”添加功能
运行 CLI 命令:
brkpt auth add change-passwordCLI 会添加一个新的 features/change-password/ 文件夹。
校验 DTO
change password 功能使用固定的请求结构。本指南已经启用了 ValidationPipe,所以只需为生成的 DTO 添加校验装饰器。
import { IsString, MinLength } from 'class-validator';
export class ChangeDto { @IsString() currentPassword!: string;
@IsString() @MinLength(6) newPassword!: string;}实现 ChangePasswordAdapter
change password 适配器从 access token 载荷中找到已登录用户,校验当前密码,并更新存储的密码。
创建 change-password.adapter.ts:
文件夹src/
文件夹brkpt-auth/
文件夹adapters/
- change-password.adapter.ts
import { Injectable } from '@nestjs/common';import * as bcrypt from 'bcrypt';
import { User } from '../../../generated/prisma/client';import { PrismaService } from '../../prisma/prisma.service';import { ChangePasswordPort } from '../features/change-password/change-password.port';import { AuthJwtPayload } from './types';
@Injectable()export class ChangePasswordAdapter implements ChangePasswordPort<User> { constructor(private readonly prisma: PrismaService) {}
findUserByJwtPayload(payload: AuthJwtPayload): Promise<User | null> { return this.prisma.user.findUnique({ where: { id: payload.sub, }, }); }
validatePassword(user: User, currentPassword: string): Promise<boolean> { return bcrypt.compare(currentPassword, user.password); }
async updatePassword(user: User, newPassword: string): Promise<void> { const password = await bcrypt.hash(newPassword, 10); await this.prisma.user.update({ where: { id: user.id }, data: { password }, }); }
extractUserIdFromJwtPayload(payload: AuthJwtPayload): number { return payload.sub; }}注册功能
更新 features.ts,把 ChangePasswordAdapter 传给 changePasswordFeature:
import { BlacklistAdapter } from './adapters/blacklist.adapter';import { ChangePasswordAdapter } from './adapters/change-password.adapter';import { CoreAdapter } from './adapters/core.adapter';import { CredentialsAdapter } from './adapters/credentials.adapter';import { MagicLinkAdapter } from './adapters/magic-link.adapter';import { OAuthAdapter } from './adapters/oauth.adapter';import { OtpAdapter } from './adapters/otp.adapter';import { SessionAdapter } from './adapters/session.adapter';import { FeatureConfig } from './common/interfaces';import { blacklistFeature } from './features/blacklist/blacklist.feature';import { changePasswordFeature } from './features/change-password/change-password.feature';import { coreFeature } from './features/core/core.feature';import { credentialsFeature } from './features/credentials/credentials.feature';import { EmailMagicLinkDriver } from './features/magic-link/drivers/email.driver';import { magicLinkFeature } from './features/magic-link/magic-link.feature';import { GithubOAuthDriver } from './features/oauth/drivers/github.driver';import { GoogleOAuthDriver } from './features/oauth/drivers/google.driver';import { oauthFeature } from './features/oauth/oauth.feature';import { EmailOtpDriver } from './features/otp/drivers/email.driver';import { otpFeature } from './features/otp/otp.feature';import { sessionFeature } from './features/session/session.feature';
export const features: FeatureConfig[] = [ coreFeature(CoreAdapter), blacklistFeature(BlacklistAdapter), credentialsFeature(CredentialsAdapter), sessionFeature(SessionAdapter), oauthFeature(OAuthAdapter, GoogleOAuthDriver, GithubOAuthDriver), otpFeature(OtpAdapter, EmailOtpDriver), magicLinkFeature(MagicLinkAdapter, EmailMagicLinkDriver), changePasswordFeature(ChangePasswordAdapter),];启动应用:
pnpm start:devnpm run start:devyarn start:devchange-password 功能新增一个端点:
| Method | Path | Description |
|---|---|---|
POST |
/auth/change-password |
修改已登录用户的密码 |
修改密码
用任意登录方式得到的 access token,发送当前密码和新密码:
POST /auth/change-passwordAuthorization: Bearer <access-token>Content-Type: application/json
{ "currentPassword": "password", "newPassword": "123456"}请求成功后,已登录用户的密码就会被修改。
密码修改后,当前会话仍然保持有效。如果启用了 session 功能,该用户的其他会话会被撤销。