如何在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
相关产品推荐
相关产品推荐

