Node/Express 的 Passport 身份验证中间件 - 如何保护所有路由

Posted

技术标签:

【中文标题】Node/Express 的 Passport 身份验证中间件 - 如何保护所有路由【英文标题】:Passport Authentication Middleware for Node/Express - How to Protect all Routes 【发布时间】:2021-12-06 23:41:34 【问题描述】:

堆栈:

前端 - Angular 12

|-- 利用 Angular/MSAL 与 Azure AD 集成 身份验证

后端:

|-- 节点JS V14.17.6 |-- Express 4.17.1 |-- 护照-Azure-AD V4.3.0(passport-azure-ad 是 Passport Strategies 的集合 帮助

您与 Azure Active 集成 |-- 身份验证策略 - BearerStrategy(保护 API 和资源) 目录) |-- Passport V0.3.2(Passport-Azure-AD 使用的 Passport 版本)

后端项目结构(为简洁起见摘录) 根目录 |-- 源 |-- 路由器(在单个 .js 文件中保存每个实体的所有模块化路由的子目录,例如 users.js、actions.js) |--index.js(应用入口点)

我正在寻找一种方法来保护我的所有路由/api端点,而不是必须将passport.authenticate应用于每个路由端点内的每个路由处理程序,这可能是每个模块化路由的“N”个路由.js 文件,如上所述。我尝试了以下方法无济于事。

    在 index.js 文件中,即我使用的应用程序入口点,例如const users = require('./routers/users') 和 app.use('/api/v1/users', users) 来挂载我的路由处理程序,我介绍了以下 app.use(passport.authenticate('oauth- Bearer', session: false )) 因为护照是一个中间件但没有乐趣

    在模块化路由处理文件中,我也尝试了以下方法: router.all('*',passport.authenticate('oauth-bearer', session: false )) 基于快速文档 router.所有人都应该在所有请求方法的路径上应用中间件或提供的函数/处理程序,在这种情况下,'*' 应该匹配所有路径,但这仍然只适用于基本路径“/”而不适用于文件中的其他路径,例如'/关系'

如果有人能开出保护所有路线的方法,将不胜感激。

【问题讨论】:

【参考方案1】:
    router.all() 函数与 router.METHOD() 方法类似,只是它匹配所有 HTTP 方法(动词)。

如果我写,router.all('/users', callback),这意味着回调将为端点/users 的每个方法(GET、POST、DELETE、PATCH、PUT 等)运行。

如果想为每条路线运行它,你需要做这样的事情 -

router.all('*', callback)

    我喜欢使用router.use() 函数,该函数专门针对此类用例。假设我的监控路由中有 2 个端点。如果我想为两者都设置身份验证保护,我喜欢这样做 -
const constant = require(__basePath + 'app/config/constant');
const router   = require('express').Router(
    caseSensitive: true,
    strict       : true
);
const monitor  = require(constant.path.module + 'monitor/monitor.controller');
const Passport      = require('passport');
const AuthGuard     = Passport.authenticate(['user', 'admin'],  session : false );

router.use(AuthGuard);

router.get(
    '/ping',
    monitor.ping
);

router.get(
    '/status',
    monitor.status
);

module.exports = 
    router: router
;

附: - 请忽略constantpath相关的东西,仅供参考。

【讨论】:

您好 Pankaj,感谢您抽出宝贵时间回答我的问题。因此,谈到 Router 实例的“all”方法,我确实熟悉它的功能。我想指出您对 passport.authenticate 的使用,不确定这是错误还是无意的遗漏;注意到您没有提供所需的第一个参数,即护照策略,因此在我的情况下,这将是一个承载策略,因为我严格需要保护资源/api 端点。如果没有提供的策略,您的上述实现将导致错误 嗨@nubianMONK,我使用的这两个策略(['user', 'admin'],,是在一个单独的护照服务文件中定义的(在主服务器文件中导入和初始化)。我只是想解释一下我如何使用router.use()【参考方案2】:

所以在寻找解决方案多天后,我终于找到了为什么我的上述实施不起作用的罪魁祸首。它归结为最近引入的通配符'*' 功能,因为它适用于 MSAL/Angular 的 protectedResourceMap。利用上面的示例,从客户端(Angular V12)实现的方式是将上述受保护的资源映射设置为:'http://localhost:3001/api/v1/*',这在逻辑上会很好转保护端点,例如

    'http://localhost:3001/api/v1/users' 'http://localhost:3001/api/v1/users/relationshp'

但我发现通配符并不像人们想象的那样工作,它几乎只会匹配上面标记为 (1.) 的第一个 url,因为这是在“users.js”路由器文件中处理的路由器处理程序,基本端点 router.get('/', (req, res, next) => ...do something );并将完全抛弃以下路由器处理程序(应匹配上面标记为 (2.) 的第二个 url),端点 router.get('/relationships', (req, res, next) => ...do something );顺便说一句,它同样在“users.js”路由器文件中实现。

节省一天客户端修复(Angular V12)的解决方案是首先删除通配符 asterix '*' 作为受保护资源映射配置的一部分,并保持原样:'http://localhost:3001/api /v1/' 并根据我的要求在服务器端(NodeJs),即保护所有路由是将以下解决方案应用于服务器解决方案“index.js”的入口点,利用护照作为全面应用于应用程序的中间件: app.use(passport.authenticate('oauth-bearer', session: false ));这种方式不需要在每个路由器处理程序文件中实现相同的。希望这对面临类似问题的人们有所帮助。

【讨论】:

以上是关于Node/Express 的 Passport 身份验证中间件 - 如何保护所有路由的主要内容,如果未能解决你的问题,请参考以下文章

Node/Express 的 Passport 身份验证中间件 - 如何保护所有路由

Node、Express、Oauth2 和 Passport 的 Angularjs CORS 问题

在 JWT 中存储秘密信息,使用 Node.js - Express 后端

无法读取 null + passport.js 的属性“正文”

Passportjs Facebook 登录流程(passport-facebook vs passport-token)

req.user 未定义 - 节点 + 快递 + 护照-facebook