Express/Passport: adminpanel authorization - node.js

Is there any way to make authorization system like this:
app.get('/admin/*', function (req, res) {
/*checks if user authorised, if not throws an error, if yes opens requested page*/
});
app.get('/admin/item', function (req, res) {
/*blah-blah-blah*/
});
app.get('/admin/category', function (req, res) {
/*blah-blah-blah*/
});
As an example I logged in and want to open /admin/item page.
I can simply get what do I want by this way, but this way generates more code:
app.get('/admin/item', function (req, res) {
/*authorization check*/
/*blah-blah-blah*/
});
app.get('/admin/category', function (req, res) {
/*authorization check*/
/*blah-blah-blah*/
});

Related

Is it possible to dynamically use a route part to call passport strategy?

Currently, I have the following code for many more oath provider:
// facebook
router.get("/facebook", passport.authenticate("facebook", { scope: ["email"] }));
router.get("/facebook/callback", passport.authenticate("facebook"), (req, res) => {
console.log(chalk.blue("went into facebook callback"));
res.redirect("http://localhost:3000/profile");
});
// github
router.get("/github", passport.authenticate("github"));
router.get("/github/callback", passport.authenticate("github"), (req, res) => {
console.log(chalk.blue("went into github callback"));
res.redirect("http://localhost:3000/profile");
});
Is there a way to unify that into an abstracted route? I.e. something like
// github
router.get("/:provider", passport.authenticate(:provider));
router.get("/:provider/callback", passport.authenticate(:provider), (req, res) => {
console.log(chalk.blue("went into {:provider} callback"));
res.redirect("http://localhost:3000/profile");
});
Update:
The following piece of code does what I want. Thx to #Usman Abdur Rehman.
function callbackDistributer(req, res, next) {
console.log(req.params);
global.provider = req.params.provider;
next();
}
router.get(
"/:provider/callback",
callbackDistributer,
(req, res, next) => {
passport.authenticate(global.provider)(req, res, next);
},
(req, res) => {
console.log(chalk.red("went into: " + global.provider));
res.redirect("http://localhost:3000/profile");
}
);
Have a middleware function going before the passport.authenticate middleware
function ownMiddleware(req,res,next){
global.provider = req.params.provider
next()
}
and then use it in the route handler as
router.get("/:provider/callback", ownMiddleware ,passport.authenticate(global.provider), (req, res) => {
console.log(chalk.blue("went into {:provider} callback"));
res.redirect("http://localhost:3000/profile");
});
I think it should work

Express router ordering for params in beginning of url path

I am using express and I want to have my user profile URLs like this: example.com/:username
However, I still need other URLs such as example.com/login and example.com/view/:id
If I order the router like this, it treats "login" as a username when a request is sent to example.com/login:
router.get('/:username', function (req, res, next) {
res.render('profile', {data: req.params.username});
})
router.get('/login', function (req, res, next) {
res.render('login', {data: null});
})
router.get('/view/:id', function (req, res, next) {
res.render('view', {data: req.params.id});
})
If I put the /:username router at the end, everything works correctly. However, if someone went to example.com/view (without an id), I need it to send an error that the view controller didn't receive an id. Instead, it sees it as a username again and instead sends an error that the username doesn't exist.
What is the cleanest way to solve this? Do I just have to add a router for all base url paths? (Something like this):
router.get('/login', function (req, res, next) {
res.render('login', {data: null});
})
router.get('/view/:id', function (req, res, next) {
res.render('view', {data: req.params.id});
})
router.get('/view', function (req, res, next) {
res.render('viewError', {data: null});
})
router.get('/:username', function (req, res, next) {
res.render('profile', {data: req.params.username});
})
I am not entirely sure if this is the right way to do it, but then again this sounds like something I might encounter and I would like it to be solved by this method until I find a better solution.
The below solution uses a single route for the path format /:value, be it login, view or any username, hence you could put in a simple if-else-if or switch to give control to respective controllers or just simply render a view from it. This way the order in which it has to be handled doesn't matter at all.
router.get("/:username", function(req, res, next) {
if (req.params.username === "login") {
res.render("login", { data: null });
} else if (req.params.username === "view") {
res.render("viewError", { data: null });
} else {
res.render("profile", { data: req.params.username });
}
});
router.get("/view/:id", function(req, res, next) {
res.render("view", { data: req.params.id });
});

How do I automatically return a 404 when a GET path doesn't exist?

I am using NodeJS, Express and Handlebars (template engine) to build a web application. Currently I'm trying to automatically redirect users whenever they enter an URL that does not exist (or whenever they might not have access to it).
The following returns the index page:
router.get('/', (req, res) => {
res.render('index/index');
});
But how do I make something like this:
router.get('/:ThisCouldBeAnything', (req, res) => {
res.render('errors/404');
});
The following example is from Github:
Say that I enter this URL:
https://github.com/thispagedoesnotexist
It automatically returns a 404. How do I implement this in my application?
Thanks in advance.
Use a middleware just after all route handlers to catch non existing routes:
app.get('/some/route', function (req, res) {
...
});
app.post('/some/other/route', function (req, res) {
...
});
...
// middleware to catch non-existing routes
app.use( function(req, res, next) {
// you can do what ever you want here
// for example rendering a page with '404 Not Found'
res.status(404)
res.render('error', { error: 'Not Found'});
});
After all your other routes you can add:
app.get('*', (req, res) => {
res.render('errors/404');
});
Alternately, you can use a middleware function after all your other middleware and routes.
app.use((req, res) => {
res.render('errors/404');
});
So you might end up with something that looks like:
//body-parser, cookie-parser, and other middleware etc up here
//routes
app.get('/route1', (req, res) => {
res.render('route1');
});
app.get('/route2', (req, res) => {
res.render('route2');
});
//404 handling as absolute last thing
//You can use middleware
app.use((req, res) => {
res.render('errors/404');
});
//Or a catch-all route
app.get('*', (req, res) => {
res.render('errors/404');
});
I see that you have express tagged. All you have to do is include a default handler that includes
res.status(404).render('404template')
For example
app.get('*', (req, res,next) => {
res.status(404).render('error.ejs')
});

Still wondering how to get Express to ignore matching route

I have this verbatim:
router.get('/top_level_questions,', function (req, res) {
res.json({success:true});
});
router.get('/:id', function (req, res) {
res.json({success:true});
});
what's happening is that a request to
/top_level_questions
will match the /:id handler. What is the official way to prevent that from happening>
The code:
router.get('/top_level_questions,', function (req, res) {
res.json({success:true});
});
Should be:
router.get('/top_level_questions', function (req, res) {
res.json({success:true});
});

how to group api in express

Here is the example:
var app = require('express')();
function validateToken(req, res, next) {
// Do something with request here
next();
};
app.get('/user/login', function(req, res) {
//code
});
app.post('/user/register', function(req, res) {
//code
})
app.put('/user/register', validateToken, function(req, res) {
//code
})
app.delete('/user/delete', validateToken, function(req, res) {
//code
})
If I have 10 api that need validToken, I should add validToken middleware 10 times, like:
app.method('......', validateToken, function(req, res) {
//code
})
app.method('......', validateToken, function(req, res) {
//code
})
....
app.method('......', validateToken, function(req, res) {
//code
})
app.method('......', validateToken, function(req, res) {
//code
})
How can I group api by using the same middleware?
Here's how to re-use the same callback function for multiple routes (like middleware):
var app = require('express')();
function validateToken(req, res, next) {
// Do something with request here
next();
};
app.get('/user/login', function(req, res) {
// code
});
app.post('/user/register', function(req, res) {
// code
});
// Be sure to specify the 'next' object when using more than one callback function.
app.put('/user/register', validateToken, function(req, res, next) {
// code
next();
});
app.delete('/user/delete', validateToken, function(req, res, next) {
// code
next();
});
Also, you can replace app.METHOD (e.g. .post, .get, .put, etc.) with app.all and your callback will be executed for any request type.
Just wrong, so do not put into mass participation of the (Google translated from: 刚才看错了,改成这样就不用放进传参了)
var group = {url:true,url:true,url:true};
app.use(function(req,res,next){
if(group[req.url]){
// Do something with request here
next();
} else {
next();
}
})

Resources