Documentation for "ensureAuthentication" "isAuthenticated" passport's functions? - express

I've been looking for a while, and can't see to find a definitive documentation source. When I search for these, the first Google results are to StackOverflow.
Are there any more middleware functions similar to this?

While not explicitly documented anywhere easily found, you can see where the the isAuthenticated and isUnauthenticated flags are set in the Passport code at https://github.com/jaredhanson/passport/blob/a892b9dc54dce34b7170ad5d73d8ccfba87f4fcf/lib/passport/http/request.js#L74.
ensureAuthenticated is not official, but can be implemented via the following:
function ensureAuthenticated(req, res, next) {
if (req.isAuthenticated())
return next();
else
// Return error content: res.jsonp(...) or redirect: res.redirect('/login')
}
app.get('/account', ensureAuthenticated, function(req, res) {
// Do something with user via req.user
});

the reason it return false is mostly because its declared below the route definition.
i am doing it in other file so i use it like this
//auth check
function auth(req,res,next){
if(req.isAuthenticated()){
next();
}
else{
res.redirect("/fail");}
}
//routes
require("./routes/myroute")(app,auth);

Related

express-validator on PUT methods

I'm creating an API and decided to use express-validator for validation (duh), I've never used this before so I'm unsure on some aspects of it so my validations might not be the best but I'm getting by.
I have built two validation middle ware using this and export them from the same folder like this:
module.exports = {
create: require('./create'),
update: require('./update')
}
So I can then do this in my router:
const validation = require('../validations/plotValidation')
// ...
router.get('/', controller.all)
router.post('/create', validation.create(), controller.create)
router.get('/:plotId', controller.read)
router.put('/:plotId/update', validation.update(), controller.update)
router.delete('/:plotId/delete', controller.delete)
// ...
I'm not good enough with express-validator to do both validate both routes with the same file, maybe I'll try it at some point, anyway.
The .post method works fine and validates everything I want it to however the .put method just seems to be ignoring every check here are is file in case you want to see the checks:
const { body, check, param } = require('express-validator');
module.exports = () => {
return [
param('plotId')
.exists().withMessage('URI requires plot id'),
body('price')
.optional()
.isObject()
]
}
As you can probably tell I only just stated it, but even with only these two tiny checks it just doesn't seem to run.
Does express-validator not work on PUT methods?
For anyone else who has this issue I solved this by using .run on my checks, you can read more about this here essentially this is the code that saved me:
// parallel processing
const validate = validations => {
return async (req, res, next) => {
await Promise.all(validations.map(validation => validation.run(req)));
const errors = validationResult(req);
if (errors.isEmpty()) {
return next();
}
res.status(400).json({ errors: errors.array() });
};
};

add middleware function to an async export

I have separated my routes with their definitions so that my routes look like this:
const router = require('express').Router();
const handle = require('../handlers');
router.post('/register', handle.register);
// The handler defines the route. Like this:
exports.register = async (req, res, next) => {
try {
const user = await db.User.create(req.body);
const {id, username} = user;
res.status(201).json({id, username});
} catch (err) {
if(err.code === 11000){
err.message ='Sorry, details already taken';
}
next(err);
}
};
This works fine. Now I need to upload images as users register (using multer middleware). A lot of the examples show multer is used like this:
router.post('/register', upload ,function (req, res, next) { //upload is the multer middleware
console.log(req.file);
})
How do I add the middleware in my case?
You add the middleware like this:
router.post('/register', upload, handle.register);
Just like the examples you see.
In My Not-So-Humble Opinion
You mention that you have separated your routes from your route handler. In my opinion this is not only misguided but completely wrong.
In the usual MVC architecture you see in other languages, the route and the route handler together makes the controller. In your design you have split your controller into two separate structures. Primarily, this makes your route handling logic and the information of what route it does it for exist in two separate files when they should be located very close to each other.
Now that you are adding middlewares you are finding out that middleawares are installed in routes and with your design it is hard to figure out what middleware is installed for your route handler.
The correct way to separate your business logic from your routes is to follow the MVC design pattern - separate your Model from your Controller (the View is free because it is basically res.json()).
In my not-so-humble opinion you should be creating a model for your user instead of separating controllers into two parts. Your user obviously need a register functionality and the register function should just succeed or fail but should not concern itself with any HTTP error handling because that is the controller's job:
exports.user = {
// .. other methods
register: async function (username, password) {
try {
const user = await db.User.create({username, password});
return user;
} catch (err) {
if(err.code === 11000){
err.message ='Sorry, details already taken';
}
throw err;
}
}
}
Then in your controller (most Express example call "route") you do:
const user = require('./user');
router.post('/register', upload , async (req, res, next) => {
try {
const user = user.register(req.body.username, req.body.password);
const {id, username} = user;
res.status(201).json({id, username});
} catch (err) {
next(err);
}
})
However, this is just my personal opinion.

How to make Vue Router Guards wait for Vuex?

So all answers I've found publicly to this question weren't very helpful and while they "worked", they were incredibly hacky.
Basically I have a vuex variable, appLoading which is initially true but gets set to false once all async operations are complete. I also have another vuex variable called user which contains user information that gets dispatched from the async operation once it gets returned.
I then also have a router guard that checks;
router.beforeEach((to, from, next) => {
if (to.matched.some(route => route.meta.requiresAuth)) {
if (store.getters.getUser) {
return next();
}
return router.push({ name: 'index.signup' });
}
return next();
});
In my initial Vue instance I then display a loading state until appLoading = false;
Now this "works" but there is a problem which is really bugging me. If you load the page, you will get a "flicker" of the opposite page you are supposed to see.
So if you are logged in, on first load you will see a flicker of the signup page. If you aren't logged in, you will see a flicker of the logged in page.
This is pretty annoying and I narrowed the problem down to my auth guard.
Seems it's pushing the signup page to the router since user doesn't exist then instantly pushes to the logged in page since user gets committed.
How can I work around this in a way that isn't hacky since it's kinda annoying and it's sort of frustrating that Vue doesn't have even the slightest bit of official docs/examples for a problem as common as this, especially since such a large number of webapps use authentication.
Hopefully someone can provide some help. :)
The router beforeEach hook can be a promise and await for a Vuex action to finish. Something like:
router.beforeEach(async (to, from, next) => {
if (to.matched.some(route => route.meta.requiresAuth)) {
await store.dispatch('init');
if (store.getters.getUser) {
return next();
}
return router.push({ name: 'index.signup' });
}
return next();
});
The 'init' action should return a promise:
const actions = {
async init({commit}) {
const user = await service.getUser();
commit('setUser', user);
}
}
This approach has the problem that whenever we navigate to a given page it will trigger the 'init' action which will fetch the user from the server. We only want to fetch the user in case we don't have it, so we can update the store check if it has the user and fetch it acordingly:
const state = {
user: null
}
const actions = {
async init({commit, state}) {
if(!state.user) {
const user = await service.getUser();
commit('setUser', user);
}
}
}
As per discussion in comments:
Best approach for you case will be if you make your appLoading variable a promise. That's how you can do things or wait for things until your app data is resolved.
Considering appLoading a promise which you initialize with your api call promise, your router hook will be like:
router.beforeEach((to, from, next) => {
appLoading.then(() => {
if (to.matched.some(route => route.meta.requiresAuth)) {
if (store.getters.getUser) {
return next();
}
return router.push({ name: "index.signup" });
}
return next();
});
});
You might want to just keep it as an export from your init code instead of keeping it in Vuex. Vuex is meant for reactive data that is shared over components.

Express Routing: multiple URLs to the same route

I'm trying to make the multiple URLs work on a single express route. How can I make the following URLs all route to the same page?
https://example.com/page-slug-name
https://example.com/page-slug-name/amp
https://example.com
https://example.com/amp
It seems like this should work but it's not:
router.get("/:slug?(/amp)?", function(req, res, next) {
if (!req.params.slug) {
req.params.slug = 'home'
}
getData(slug, function(err, data){
res.render('index', data)
});
});
You can have it in single express route by placing multiple URLS inside an array.
In your case, this will be
app.get(['/', '/:slug', '/amp', '/:slug/amp'], function(req, res, next) {
if (!req.params.slug)
req.params.slug = 'home'
getData(slug, function(err, data){
res.render('index', data)
});
);
Instead of using an anonymous function as the route's controller, you can give it a name and pass the name to router.get. You can then have several router.gets that points to the same function.
function slugController(req, res, next) {
if (!req.params.slug) {
req.params.slug = 'home'
}
getData(slug, function(err, data){
res.render('index', data)
});
});
router.get("/page-slug-name", slugController);
router.get("/page-slug-name/amp", slugController);
router.get("/", slugController);
router.get("/amp", slugController);
This works best if there only are a couple of routes.
If you have a ton of routes you have to use the regex stuff that's mentioned in the manual. I don't see any pattern in your URLs though, so it's a bit hard to come up with a good solution using regex.

Sails.js Policies, is there an OR operator to allow an action if one of a group of policies succeeds?

When configuring policies in sails in config/policies.js such as:
ActivityController: {
create: ['authenticated'],
update: ['authenticated', 'isActivityOwner'],
destroy: ['authenticated' ,'isActivityOwner']
}
Is there any functionality that would allow me to grant access to the action provided one or more of a group of policies succeeds maybe something like:
ActivityController: {
create: ['authenticated'],
update: ['authenticated', {or:['isActivityOwner', 'isAdmin']}],
destroy: ['authenticated' ,'isActivityOwner']
}
Alternatively is it possible to create composite policies so that in one policy I may check one or more other policies?
If both of these options seem like poor solutions, can you suggest an approach that would would be considered better practice?
Forgive me if this is a bit obvious but I'm fairly new to sails and node in general, and thanks in advance for any help!
I haven't found any official support for operators in sails policies but here is what I am doing.
ActivityController: {
update: ['authenticated', 'orActivityOwner', 'orAdmin', orPolicy],
}
Both orActivityOwner and orAdmin return next() as if they are valid. But they also set a boolean value to a session variable. Remember, policies are executed from left to right. I added an orPolicy to the end which will then evaluate the state of our session variable.
check out sails-must:
ActivityController: {
create: 'authenticated',
update: ['authenticated', must().be.the.owner.or.be.a.member.of('admins')],
destroy: ['authenticated', must().be.the.owner]
}
I've created a sails hook to be able to add parameters to policies:
https://github.com/mastilver/sails-hook-parametized-policies
I've setup an example where I defined an or policy:
module.exports = function(firstPolicy, secondPolicy){
return function(req, res, next){
var fakeRes = {};
for(var i in res){
if(i === 'forbidden'){
// override the functions you want the `or` factory to handle
fakeRes[i] = function(){
secondPolicy(req, res, next);
};
}
else{
fakeRes[i] = res[i];
}
}
firstPolicy(req, fakeRes, next);
}
}
Which you can use that way:
ActivityController: {
create: ['authenticated'],
update: ['authenticated', 'or(isActivityOwner, isAdmin)'],
destroy: ['authenticated' ,'isActivityOwner']
}
Just to complete the previous answer, that works like a charm :
Piece of information
But they also set a boolean value to a session variable
I myself prefer setting this boolean to the req object, that :
Is more semantic (access granted or not to ressource for the request, not for entire session)
Does not requires me to manually reset this variable
(I should add that, if you DO want to use session like in #Travis solution , the last orPolicy policy must reset (even unset) the variable in order to protect the next request)
My implementation
config/policies.js :
MyController: {
find: ['orIsTest1', 'orIsTest2', 'protectedResourceGranted']
}
api/policies/orIsTest1.js :
module.exports = function(req, res, next) {
req.protectedResourceGranted = req.protectedResourceGranted || WHATEVERFIRSTTEST;
return next();
};
api/policies/orIsTest2.js
module.exports = function(req, res, next) {
req.protectedResourceGranted = req.protectedResourceGranted || WHATEVERSECONDTEST;
return next();
};
api/policies/protectedResourceGranted.js
module.exports = function(req, res, next) {
if(req.protectedResourceGranted) {
return next();
}
return res.forbidden();
};
NB: Just answering 'cause I haven't got enough reputation to comment.
The other answers here work great, but here is an implementation that I find slightly cleaner.
Instead of creating policies designed for an OR situation that call next() even though they should fail, you can modify your existing policies to use in an AND/OR context, while hardly changing their behavior. Then create a composite policy (like the OP suggested) that checks the modified existing policies.
config/policies.js with example controllers and policies:
AdminController: {
adminDashboard: 'isAuthenticated',
},
ItemController: {
findOne: 'isPublishedOrIsAuthenticated'
}
api/policies/isAuthenticated.js and api/policies/isPublished.js and any other policy you want to use as a part of an AND/OR check:
If next was set to the true boolean (as opposed to a callback), just return true or false before the policy would normally return next(), res.notFound(), etc.
module.exports = function(req, res, next) {
// do some checking
if(next === true) return true; // or return false
return next();
};
Note that we need to use the triple-equals sign here.
api/policies/isPublishedOrIsAuthenticated.js
module.exports = function(req, res, next) {
var isPublished = require('./isPublished.js');
var isAuthenticated = require('./isAuthenticated.js');
// This reads like what we are trying to achieve!
// The third argument in each call tells the function to return a boolean
if(isPublished(req, res, true) || isAuthenticated(req, res, true))
return next();
return res.notFound();
};