简体   繁体   中英

Passport Authentication Middleware for Node/Express - How to Protect all Routes

Stack:

Front End - Angular 12

|-- Leveraging Angular/MSAL to integrate with Azure AD for authentication

Back End:

|-- Node JS V14.17.6
|-- Express 4.17.1
|-- Passport-Azure-AD V4.3.0 (passport-azure-ad is a collection of Passport Strategies to help

you integrate with Azure Active |-- Authentication Strategy - BearerStrategy (Protects APIs and Resources) Directory) |-- Passport V0.3.2 (Passport version leveraged by Passport-Azure-AD)

Back End Project Structure (Excerpt shown for brevity) Root Directory |-- src |-- routers(Sub directory that holds all modularized routes per entity in individual .js files eg users.js, actions.js) |--index.js(Application entry point)

I'm looking for a way to protect all my routes/api endpoints, rather than having to apply the passport.authenticate to each route handler within each of the route endpoints which could be "N" number of routes per modularized route .js files as expressed above. I have tried the following below to no avail.

  1. Within the index.js file, ie the applications entry point, in which I use eg const users = require('./routers/users') and app.use('/api/v1/users', users) to mount my route handlers, I introduced the following app.use(passport.authenticate('oauth-bearer', { session: false })) since passport is a middleware but no joy

  2. Within the modularized route handling files, I tried the following as well: router.all( '*' ,passport.authenticate('oauth-bearer', { session: false })) based on the express documentation, router.all should apply a middleware or provided function/handler at a path for all request methods and in this case the '*' should match all paths, but still this only worked for the base path '/' and not others in the file eg '/relationships'

If anyone can prescribe a way to protect all routes, it will be greatly appreciated.

  1. The router.all() function is just like the router.METHOD() methods, except that it matches all HTTP methods (verbs).

If I write, router.all('/users', callback) , it means, the callback will run for each method (GET,POST,DELETE,PATCH,PUT etc) for endpoint /users .

If want to run it for each route, you would need to do something like this -

router.all('*', callback)

  1. I like to use router.use() function, which is specifically for such use cases. Suppose, I have 2 endpoints in my monitor routes. If I want to put an authentication guard for both, I like to do this -
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
};

PS - Please ignore, constant and path related stuff, this is just for reference.

So after many a days, seeking a solution, I finally found the culprit as to why my implementation as stated above did not work. It boils down to the recent introduction of the wildcard '*' feature as it applies to MSAL/Angular's protectedResourceMap. Leveraging the example above, the way this is implemented from the client(Angular V12) is by setting the aforementioned protected resource map to: 'http://localhost:3001/api/v1/*' and this one will logically think well in turn protect endpoints such as

  1. 'http://localhost:3001/api/v1/users'
  2. 'http://localhost:3001/api/v1/users/relationshp'

but what I uncovered is that the Wildcard doesn't quite work as one will think, it pretty much will just match the first url above tagged (1.) as this is handled within the "users.js" router file by the router handler, base endpoint router.get('/', (req, res, next) => {...do something }); and will totally jettison the following router handler(Should match Second url above tagged (2.)), endpoint router.get('/relationships', (req, res, next) => {...do something }); which by the way is equally implemented within the "users.js" router file.

Solution that saved the day client fix(Angular V12) was to first to remove the Wildcard asterix '*' as part of the Protected Resource Map configuration and just kept it as such : 'http://localhost:3001/api/v1/' and on the server side(NodeJs) per my requirements ie protect all routes was to apply the following solution to the entry point of the server solution "index.js" leveraging passport as a middleware applied to the application across the board: app.use(passport.authenticate('oauth-bearer', { session: false })); this way not needing to implement same within each router handler file. Hope this helps folks out there facing similar issues.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM