跳转到内容

修改密码

让已登录用户修改自己的密码。

本指南添加 change-password 功能。

change-password 功能让已登录用户通过提供当前密码和新密码来更新密码。

添加功能

运行 CLI 命令:

Terminal window
brkpt auth add change-password

CLI 会添加一个新的 features/change-password/ 文件夹。

校验 DTO

change password 功能使用固定的请求结构。本指南已经启用了 ValidationPipe,所以只需为生成的 DTO 添加校验装饰器。

src/brkpt-auth/features/change-password/dto/change.dto.ts
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
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:

src/brkpt-auth/features.ts
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),
];

启动应用:

Terminal window
pnpm start:dev

change-password 功能新增一个端点:

Method Path Description
POST /auth/change-password 修改已登录用户的密码

修改密码

用任意登录方式得到的 access token,发送当前密码和新密码:

POST /auth/change-password
Authorization: Bearer <access-token>
Content-Type: application/json
{
"currentPassword": "password",
"newPassword": "123456"
}

请求成功后,已登录用户的密码就会被修改。

密码修改后,当前会话仍然保持有效。如果启用了 session 功能,该用户的其他会话会被撤销。