You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在TypeScript中结合JWT实现修改密码API

实现步骤

1. 编写通用JWT鉴权中间件

所有需要登录态的接口都要先经过这个中间件校验,会自动适配前端从Authorization头或者Cookie传的JWT:

import { Request, Response, NextFunction } from 'express';
import jwt from 'jsonwebtoken';
import config from './你的config配置文件路径';

// 鉴权中间件,校验通过会把用户信息挂载到req.user上
export const auth = async (req: Request, resp: Response, next: NextFunction) => {
  let token: string | undefined;
  // 优先从Authorization头取token(适配本地存储场景)
  if (req.headers.authorization?.startsWith('Bearer ')) {
    token = req.headers.authorization.split(' ')[1];
  } 
  // 头里没有的话从Cookie取(适配Cookie存储场景)
  else if (req.cookies?.jwt_token) {
    token = req.cookies.jwt_token;
  }

  if (!token) {
    return resp.status(401).json({ status: 'error', message: '未登录,无权限访问' });
  }

  try {
    // 校验token合法性
    const decoded = jwt.verify(token, config.token.secret) as { id: string; username: string };
    // 挂载用户ID到请求对象上,后续接口直接用
    req.user = { id: decoded.id, email: decoded.username };
    next();
  } catch (error) {
    return resp.status(401).json({ status: 'error', message: 'token无效或已过期' });
  }
}

注意:如果要使用Cookie存储的方案,需要先安装cookie-parser依赖,并且在express入口文件里注册中间件:

import cookieParser from 'cookie-parser';
app.use(cookieParser());

如果TS报req.user不存在的错误,需要扩展express的Request类型,在项目里新建typings/express/index.d.ts文件:

declare namespace Express {
  interface Request {
    user: {
      id: string;
      email: string;
    }
  }
}

2. (可选)优化登录接口支持Cookie回写

如果要使用Cookie存储JWT的方案,不需要前端手动存,可以直接在登录接口里把token写入响应Cookie:

export let login=async(req:Request,resp:Response)=>{
  var {email , password} = req.body;
  try{
    const user=await User.findOne({email}).lean();
    if(!user){
        return resp.json({message:"user not found"})
    }
    if(await bcryptjs.compare(password,user.password)){
        const token=jwt.sign(
            {
                id:user._id,
                username:user.email
            },config.token.secret)
        // 写入Cookie,httpOnly防止XSS盗取,生产环境可以开secure只在HTTPS下传输
        resp.cookie('jwt_token', token, {
          httpOnly: true,
          maxAge: 7 * 24 * 60 * 60 * 1000, // 7天有效期
          secure: process.env.NODE_ENV === 'production'
        })
        return resp.json({status:'ok',data:token})
    }
    return resp.json({status:'error',data:'comming soon'})
  }catch(error){
     console.log(error);
  }
}

3. 实现修改密码接口

直接复用上面的鉴权中间件,接口里直接从req.user拿当前登录的用户ID即可:

import bcryptjs from 'bcryptjs';
import { auth } from './上面的中间件文件路径';
import User from './你的User模型文件路径';

// 路由注册的时候先过auth中间件
app.post('/change_password', auth, async (req: Request, resp: Response) => {
  try {
    const { old_password, new_password } = req.body;
    // 校验参数是否存在
    if (!old_password || !new_password) {
      return resp.json({ status: 'error', message: '旧密码和新密码不能为空' });
    }
    // 查当前登录的用户
    const user = await User.findById(req.user.id);
    if (!user) {
      return resp.json({ status: 'error', message: '用户不存在' });
    }
    // 校验旧密码是否正确
    const isOldPwdValid = await bcryptjs.compare(old_password, user.password);
    if (!isOldPwdValid) {
      return resp.json({ status: 'error', message: '旧密码输入错误' });
    }
    // 新密码加密后更新
    const encryptedNewPwd = await bcryptjs.hash(new_password, 10);
    await User.findByIdAndUpdate(req.user.id, { password: encryptedNewPwd });
    // 修改成功后可以清理Cookie(可选,强制用户重新登录)
    resp.clearCookie('jwt_token');
    return resp.json({ status: 'ok', message: '密码修改成功,请重新登录' });
  } catch (error) {
    console.log(error);
    return resp.json({ status: 'error', message: '修改失败,请重试' });
  }
})

前端调用注意事项

  • 如果用本地存储JWT的方案:登录成功后把token存在localStorage里,调用修改密码接口的时候,请求头里带上Authorization: Bearer ${localStorage.getItem('token')}
  • 如果用Cookie存储JWT的方案:前端调用登录和修改密码接口的时候都要开启withCredentials: true,不需要手动处理token的存储和传输

内容的提问来源于stack exchange,提问作者Rohit kumar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.16 07:15:03