Express req.user 即使在经过身份验证的中间件后面也是可选的



当将Passport与Express一起使用时,Typescript认为在使用身份验证中间件时,req.user可能在路由中未定义。使用身份验证中间件时,我希望在所有情况下都定义 req.user,否则中间件将返回 401 未经授权的响应。

如果路由使用如下身份验证中间件:

app.use( '/users', passport.authenticate('bearer', { session: false }), usersRouter ); 

/users 中的路由不应使用户可能未定义,因为它永远不会定义。

如何在不声明用于每个路由的自定义请求接口的情况下实现这一点?

简而言之,你不能让 Typescript 理解你的中间件是否设置req.user,因为 TS 不"理解"中间件在 Express 中的工作方式。但是,您可以扩展请求接口,并在知道已设置值的位置使用自定义实现(即在经过身份验证的路由中)。

定义自定义接口:

import { Request } from 'express';
import { YourUserDefinitionInterface } from './your-user-definition.interface.ts';
export interface AuthenticatedRequest extends Request {
user: YourUserDefinitionInterface 
}

在路由中使用它:

// The below route is behind the auth middleware
app.get('/some-path', (req: AuthenticatedRequest) => {
// Your handling logic here
});

我为此苦苦挣扎了很长一段时间。最后,最简单的解决方案是在Request类型上创建新的自定义属性authenticatedUser

global.d.ts文件中:

declare namespace Express {
export interface User {
id: string;
otherStuff: any;
}
interface Request {
authenticatedUser: User;
}
}

然后在应用程序代码中,我可以调用:

const someHandler: Handler = async (req, res) => {
const { authenticatedUser: user } = req;
logUser(user.id); // no TS errors!
}

简而言之javascript在例如req.user={name:"Jane",email:"janeDoe@gmail.com"中动态设置属性相当容易。但来到Typescript就没那么直接了。我解决此问题的解决方法是在请求对象上设置dynamic property,并具有在所有请求周围使用的自定义express.Request类型

import {Request,Response,NextFunction} from "express"
export type RequestType = {
[prop: string]: any
} & Request
export const Authorize = async (
req: RequestType,
res: Response,
next: NextFunction,
) => {
try {
const AuthHeaderToken = req.headers.authorization
if (!AuthHeaderToken)
throw new ErrorResponse('Auth header token not provided', 400)
const token = AuthHeaderToken.split(' ')[1]
return jwt.verify(token, SECRET_KEY!, (err, payload) => {
if (err)
throw new ErrorResponse('Invalid or expired auth token', 400)
req.user = payload
return next()
})
} catch (err) {
return next(err)
}
}

对于此实现,您可以动态地将任何属性设置为 Request 对象。希望它对你有用

最新更新