即使在经过身份验证的中间件之后,Express req.user 也是可选的
Posted
技术标签:
【中文标题】即使在经过身份验证的中间件之后,Express req.user 也是可选的【英文标题】:Express req.user is optional even behind an authenticated middleware 【发布时间】:2021-04-08 09:31:58 【问题描述】:当使用 Passport 和 Express 时,Typescript 认为 req.user 在使用 auth 中间件时可能在路由内未定义。使用身份验证中间件时,我希望在所有情况下都定义 req.user,否则中间件将返回 401 未授权响应。
如果路由使用这样的授权中间件:
app.use( '/users', passport.authenticate('bearer', session: false ), usersRouter );
/users 中的路由不应该有可能未定义的用户,因为它永远不会。
如何在不为每个路由声明要使用的自定义请求接口的情况下实现这一点?
【问题讨论】:
您能否提供minimal reproducible example - 您希望中间件在哪里更改处理程序中请求对象的类型? 如果路由使用这样的认证中间件:app.use('/users', passport.authenticate('bearer', session: false ), usersRouter); /users 中的路由不应该有可能未定义的用户,因为它永远不会。 那应该如何改变 userRouter 或请求的类型?路由器类型不是由它使用的地方定义的。 这就是我的问题,我不确定它是如何实现的,但我很好奇它是否可能。否则,我是否必须在每条路由的顶部执行 if (!req.user) return res.status(401).send() 之类的操作? 你可以像库一样扩展 Express 命名空间的 Request 接口,使用户成为非可选的,但它不能警告你 不是的路由i> 已通过身份验证。 【参考方案1】:简而言之,您无法让 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
);
【讨论】:
【参考方案2】:简单地说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 对象设置任何属性。希望对你有用
【讨论】:
以上是关于即使在经过身份验证的中间件之后,Express req.user 也是可选的的主要内容,如果未能解决你的问题,请参考以下文章
如何使用基于 JWT 令牌的 express 获取经过身份验证的用户信息
Node/Express 的 Passport 身份验证中间件 - 如何保护所有路由