使用Passport和TypeScript进行Node.js身份验证:找不到req.user

8
我目前正在使用typescript、WebStorm、passport和jwt为node.js微服务应用程序开发认证服务。尝试将路由添加到“/api/login”时,我注意到智能提示好像无法识别req.user的用户对象或req.header.authorization的授权对象。例如,以下方法因找不到用户对象而无法正常工作:
private generateToken(req: Request, res: Response, next: NextFunction){
req.token = jwt.sign({
  id: req.user.id,
  firstname: req.user.firstname,
  lastname: req.user.lastname,
  roles: req.user.roles
}, process.env.AUTH_KEY, {
  expiresIn: "7d"
});
return next();
}

我正在使用来自Express的Request对象:

import { NextFunction, Request, Response, Router } from "express";

我需要使用不同的Request对象吗?

另外,如果我需要强制对某些api路由进行身份验证,但锁定其他路由,该如何使用passport-jwt实现?我知道有一个express-unless包可以用于express-jwt。


您运行此代码时是否遇到错误,或者您的问题是关于智能感知方面的?由于Javascript不易静态分析,因此许多智能感知无法捕获的内容。 - Joe Frambach
它正在智能感知中变成红色,当我将鼠标悬停在上面时,会出现“未解析的变量user”。我以为由于我正在使用TypeScript,它会找到这个变量。 - user1790300
我不认为智能感知会那么聪明,很抱歉让你失望了。这一切仍然很新颖,有些部分还是未知的。这就是使用新技术的一部分 :) - Joe Frambach
2个回答

7

不确定为什么这个问题被踩了,可能是因为它应该是两个单独的问题。

您可以扩展Express的类型声明。

扩展express类型定义

在源目录中添加一个名为library-ext.d.ts的文件,并添加以下内容。

declare module 'express' {
  export interface Request {
        user?: any;
    }
}

对于req.header.authorization,请尝试使用:req.headers['authorization']。注意有个's'。
与一般身份验证相关:
这取决于您注册的用户是否也可以使用guest路由。如果您在访客路由上不需要身份标识,则只需在已验证的路由上注册护照身份验证中间件,或将路由拆分为单独的路由器即可。这很简单,只需搜索堆栈溢出或查看文档即可。
更复杂的情况是,当您需要认证和非认证用户都可以访问某个路由时 - 例如,访客或已认证的客户向购物车添加物品。不幸的是,passport-jwt会在没有令牌的情况下拒绝请求并返回401错误,因此我发现最简单的方法是使用中间件添加已知值来表示匿名请求。然后只需确保该中间件位于受影响路由中的护照身份验证之前即可。以下是一个片段供您参考:
CoreCtrl
class CoreCtrl {

  simulateAnonymous(req, res, next) {
    if (!req.headers.authorization) {
      req.headers.authorization = 'Bearer guest-token';
    }
    return next();
  }

}

在你的Express设置中的某个地方:
setupRouters() {
    // the public and admin routers are bound to the application
    const coreCtrl = new CoreCtrl(this.serverOpts);
    const anonymousCtrl = coreCtrl.simulateAnonymous.bind(coreCtrl);
    this.routers.admin.use(anonymousCtrl);
    this.routers.admin.use(passport.authenticate('UserBearer', { session: false }));
    this.routers.public.use(anonymousCtrl);
    this.routers.public.use(passport.authenticate('CustomerBearer', { session: false }));
  }

请注意,我在此处设置了公共和管理员的分开路由器,这不是必要的,只是为了说明如何做到这一点。
然后,在承载策略中,您将会有类似于以下代码的一些内容。
/**
* Run the strategy
*
* @param token {String} The JWT Token
* @param done {Callback} Callback function
*/
exec(token:string, done):Promise<any> {
  // this is the workaround to support not passing a token for guest users.
  if (token === 'guest-token') {
    return done(null, {
      userId: 'guest',
      roles: ['guest']
    });
  }
  // otherwise decode the token and find the user.
}

最后,在一些后续的中间件中,您可以检查“guest”角色是否有权访问受保护的资源。我建议使用acl模块来管理基于角色的ACL列表。


0
Property 'isAuthenticated' does not exist on type 'Request'.

谷歌搜索会带您来到这里,解决方案是在Express中使用请求/响应类型。我的代码默认使用了Fetch API的请求/响应定义。

import { Express, NextFunction, Request, Response } from 'express'

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接