如何使用PassportJS保护API端点?

时间:2013-11-15 11:35:25

标签: angularjs express passport.js

我的应用使用Express和AngularJS。我正在使用express通过静态来处理角度代码的基本网络搜索。角度代码使用命中由express托管的API端点的服务。我只希望在用户通过身份验证后可以访问API端点。我如何通过PassportJS实现这一目标?

4 个答案:

答案 0 :(得分:17)

我已经在github上上传了一个我一直在研究的Angular-Express project

它仍在进行中。我希望它有所帮助。

它使用PassportJ进行用户身份验证,是服务器端授权的基本示例。它演示了如何仅对经过身份验证的用户访问API调用,或仅对具有admin角色的用户进行访问。这是通过server/routes.js调用ensureAuthenticated

中定义的中间件函数ensureAdminserver/authentication.js来实现的。 在routes.js中

// anybody can access this 
app.get('/api/test/users', 
        api.testUsers);


// only logged-in users with ADMIN role can access this 
app.get('/api/users',          
        authentication.ensureAdmin,
        api.testUsers);

// only logged-in users can access this
app.get('/api/books', 
        authentication.ensureAuthenticated, 
        api.books);

在authentication.js

ensureAuthenticated: function(req, res, next) {
    if (req.isAuthenticated()) {
       return next();
    } else {
       return res.send(401);
    }
},

ensureAdmin: function(req, res, next) {
  // ensure authenticated user exists with admin role, 
  // otherwise send 401 response status
  if (req.user && req.user.role == 'ADMIN') {
      return next();
  } else {
      return res.send(401);
  }
},

答案 1 :(得分:2)

我还没有使用passportjs,但我刚刚完成了你想做的事情。这是我的示例配置:

// Example configuration
var express = require('express');
var routes = require('./routes');
var app = express();

app.configure(function(){
    app.use(express.bodyParser());
    app.use(express.cookieParser('shhhh, very secret'));
    app.use(express.session());
    app.use(express.favicon());
    app.use(express.logger('dev'));
    app.use(express.compress());
    app.use('/', express.static(expressAppdir)); // look for overrides on express server 1st
    app.use('/', express.static(appDir));
   // app.use(express.methodOverride()); 
    app.use(app.router);

    app.use(function(req, res, next){
      var err = req.session.error
        , msg = req.session.success;
      delete req.session.error;
      delete req.session.success;
      res.locals.message = '';
      if (err) res.locals.message = '<p class="msg error">' + err + '</p>';
      if (msg) res.locals.message = '<p class="msg success">' + msg + '</p>';
      next();
    });

});

app.configure(function() {
    // gets
    app.get('/', routes.root);
    app.get('/login', routes.login);
    app.get('/logout', routes.logout);    

    app.get('/restricted/test/:slug', restrict, routes.restrictedGet); // must be last API route, slug is any request on the end of the routes that is requested.

    app.post('/login', routes.loginPost);
});

function restrict(req, res, next) {
  console.dir('restrict called');
  if (req.session.user) {
    next();
  } else {
    req.session.error = 'Access denied!';
    res.redirect('/login');
  }
}

//Routes.js file

// my dummy login (in a separate file)

var passport = require('passport')
  , LocalStrategy = require('passport-local').Strategy;

  passport.use(new LocalStrategy(
  function(username, password, done) {
    User.findOne({ username: username }, function (err, user) {
      if (err) { return done(err); }
      if (!user) {
        return done(null, false, { message: 'Incorrect username.' });
      }
      if (!user.validPassword(password)) {
        return done(null, false, { message: 'Incorrect password.' });
      }
      return done(null, user);
    });
  }
));

exports.restrictedGet = function (req, res, next) {
  console.dir('reached restricted get');

  var slug = req.params.slug;
  console.dir(req.route);

  if(req.route.path.indexOf('test')!=-1)
  {
    namedQuery['testFunction'](req,res,next);
  }
  else
  {
    res.status(404).send('no route found. Route requested: ' + req.route.path);
  }

  // do something with your route here, check what's being appended to the slug and fire off the appropriate function.
};

exports.login = function(req, res, next) {
  res.sendfile(serverBase + "/static/public/login.html");
};

exports.logout = function(req, res, next) {
     req.session.destroy(function(){
      res.redirect('/');
    });
};

// this is where you would hook in your passportjs stuff to do hashing of inputted text and compare it to the hash stored in your db etc.
// I use my own simple authentication funciton right now as i'm just testing.

exports.loginPost = function(req, res, next) {
  authenticate(req.body.username, req.body.password, function(err, user){
    console.log('Reached login user: ', user);
    if (user) {
          // Regenerate session when signing in
          // to prevent fixation 
          req.session.regenerate(function(){

            req.session.user = user;
            req.session.success = 'Authenticated as ' + user.name
            + ' click to <a href="/logout">logout</a>. '
            + ' You may now access <a href="/restricted">/restricted</a>.';
              res.redirect('/');
            });
        } else {
          req.session.error = 'Authentication failed, please check your '
          + ' username and password.'
          + ' (use "tj" and "foobar")';
          res.json({success: false});
          res.redirect('/login');
        }
      });
};

// You could now do this with passport instead:
exports.loginPost = function(req, res, next) {
  passport.authenticate('local'), function(err, user){
    console.log('Reached login user: ', user);
    if (user) {
          // Regenerate session when signing in
          // to prevent fixation 
          req.session.regenerate(function(){

            req.session.user = user;
            req.session.success = 'Authenticated as ' + user.name
            + ' click to <a href="/logout">logout</a>. '
            + ' You may now access <a href="/restricted">/restricted</a>.';
              res.redirect('/');
            });
        } else {
          req.session.error = 'Authentication failed, please check your '
          + ' username and password.'
          + ' (use "tj" and "foobar")';
          res.json({success: false});
          res.redirect('/login');
        }
      };
};

function authenticate(name, pass, fn) {

  var user = { name:name, password: pass }
  return fn(null,user);

};

这是我从我的代码中获得的很多代码:http://www.breezejs.com/samples/zzahttp://passportjs.org/guide/authenticate/

希望这有帮助!

修改

我忘了提到,对于角度方面,我只有一个简单的表格,将用户和密码的值发布回登录帖子端点,因为getEndpoint受限制,快递应用程序将处理其余的身份验证和限制对你而言的一面。如果我能得到任何进一步的帮助,请不要犹豫。

答案 2 :(得分:1)

这是检查用户是否已登录的非常简单的方法。

假设您设置了这样的中间件:

const authMiddleware = (req, res, next) => {
    if(req.headers.authorization == undefined) { // or whatever auth strategy you're using
        req.isAuthenticated = false;
    }
    else {
        // your own code to fetch user
        req.isAuthenticated = true;
    }

    next();
}

app.use(authMiddleware);

您可以创建另一个简单的中间件来限制某些路由:

const checkIsAuth = (req, res, next) => {
    req.isAuthenticated ? next() : res.sendStatus(401);
}

router.get('/foo', checkIsAuth, fooController.getAll);

答案 3 :(得分:0)

我知道两种解决方案

angular-client-side-authangular-http-auth

你可以在github上找到它