简体   繁体   中英

Passport.js optional authentication

Is there an optional authentication middleware from Passport.js?

Let's say I have a route, /api/users . I want to give just a list of users to the public, but to authenticated people, I want to add more fields.

Currently I have just a dumb custom method that does the same thing, but I wonder if:

  • Passport.js already provides such thing or
  • how can I make this a part of passport, like a plugin or so.

My method, roughly, looks like

function optionalAuth(req, res, next) {

    var authHeader = req.headers.authorization;
    var token = parseToken(authHeader); // just getting the OAuth token here
    if(!token) {

        return next();
    }
    User.findOne({
        token: token
    }, function(err, user) {

        if(err) {
            return res.json(401, {message: 'auth expired'});
        };
        if(user) {
            req.user = user;
        }
        next();
    });
}

This, however, seems dumb to me, and also not in passport-auth-strategies.js or some other auth layer where I think it should be. What is the better way to do it?

Bonus points for telling me if I'm doing the proper thing returning 401 if I find a token but it's invalid :)

Here's a simple PoC:

var express       = require('express');
var app           = express();
var server        = app.listen(3012);
var passport      = require('passport');
var LocalStrategy = require('passport-local').Strategy;

app.use(passport.initialize());

passport.use(new LocalStrategy(function(username, password, done) {
  if (username === 'foo' && password === 'bar') {
    return done(null, { username : 'foo' });
  }
  return done(null, false);
}));

app.get('/api', function(req, res, next) {
  passport.authenticate('local', function(err, user, info) {
    var data = { hello : 'world' };
    // Only if the user authenticated properly do we include secret data.
    if (user) {
      data.secret = '3133753CR37';
    }
    return res.send(data);
  })(req, res, next);
});

It's calling passport.authenticate 'manually' in the /api endpoint. That way, you get more control over how to deal with authentication error (which—in your situation—shouldn't be treated as errors but as a way of limiting the output).

Here's the output without proper authentication:

$ curl 'localhost:3012/api?username=foo&password=wrong'
{"hello":"world"}

And here's with:

$ curl 'localhost:3012/api?username=foo&password=bar'
{"hello":"world","secret":"3133753CR37"}

To use as a middleware:

var middleware = function(req, res, next) {
  passport.authenticate('local', function(err, user, info) {
    req.authenticated = !! user;
    next();
  })(req, res, next);
};

app.get('/api', middleware, function(req, res, next) {
  var data = { hello : 'world' };
  if (req.authenticated) {
    data.secret = '3133753CR37';
  }
  return res.send(data);
});

Might be late now, but there's an anonymous Passport strategy to allow exactly this. That way the public routes can either take authentication or not, but when they do you'll still have all of the information associated with the authenticated user. Check it out here: https://github.com/jaredhanson/passport-anonymous

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