Angular JS + Node JS + Passport + Spring OAuth2 Autenticación / Autorización

Soy nuevo en PassportJS y AngularJS y tengo una duda sobre cómo proceder con esta autorización.

Tengo la API REST de Spring protegida por Oauth2, pero tengo que enviar credenciales de usuario juntas como esta:

[http://localhost:8080/myapp/oauth/token] grant_type=password&username=email&password=password&client_id=09e749d8309f4044&client_secret=189309492722aa5a&scope=read 

En el cliente, mi aplicación utilizo el pasaporte y quiero autorizar / autenticar a mis usuarios, ¿cómo puedo crear una estrategia para esto?

Enviaré aquí mi configuración de servidor y mi seguridad Lib.

Servidor.js

 var fs = require('fs'); var http = require('http'); var https = require('https'); var privateKey = fs.readFileSync(__dirname + '/cert/privatekey.pem').toString(); var certificate = fs.readFileSync(__dirname + '/cert/certificate.pem').toString(); var credentials = {key: privateKey, cert: certificate}; var express = require('express'); var config = require('./config.js'); var passport = require('passport'); var security = require('./lib/security'); var xsrf = require('./lib/xsrf'); var protectJSON = require('./lib/protectJSON'); require('express-namespace'); var app = express(); var secureServer = https.createServer(credentials, app); var server = http.createServer(app); // Serve up the favicon app.use(express.favicon(config.server.distFolder + '/favicon.ico')); // First looks for a static file: index.html, css, images, etc. app.use(config.server.staticUrl, express.compress()); app.use(config.server.staticUrl, express['static'](config.server.distFolder)); app.use(config.server.staticUrl, function(req, res, next) { res.send(404); // If we get here then the request for a static file is invalid }); app.use(protectJSON); app.use(express.logger()); // Log requests to the console app.use(express.bodyParser()); // Extract the data from the body of the request - this is needed by the LocalStrategy authenticate method app.use(express.cookieParser(config.server.cookieSecret)); // Hash cookies with this secret app.use(express.cookieSession()); // Store the session in the (secret) cookie app.use(passport.initialize()); // Initialize PassportJS app.use(passport.session()); // Use Passport's session authentication strategy - this stores the logged in user in the session and will now run on any request app.use(xsrf); // Add XSRF checks to the request security.initialize(config.oauth.authorize_url, config.oauth.access_token, config.oauth.apiKey, config.oauth.secretKey, config.oauth.scopereq); // Add a Oauth strategy for handling the authentication app.use(function(req, res, next) { if ( req.user ) { console.log('Current User:', req.user.firstName, req.user.lastName); } else { console.log('Unauthenticated'); } next(); }); app.post('/login', security.login); app.post('/logout', security.logout); // Retrieve the current user app.get('/current-user', security.sendCurrentUser); // Retrieve the current user only if they are authenticated app.get('/authenticated-user', function(req, res) { security.authenticationRequired(req, res, function() { security.sendCurrentUser(req, res); }); }); // Retrieve the current user only if they are admin app.get('/admin-user', function(req, res) { security.adminRequired(req, res, function() { security.sendCurrentUser(req, res); }); }); // This route deals enables HTML5Mode by forwarding missing files to the index.html app.all('/*', function(req, res) { // Just send the index.html for other files to support HTML5Mode res.sendfile('index.html', { root: config.server.distFolder }); }); // A standard error handler - it picks up any left over errors and returns a nicely formatted server 500 error app.use(express.errorHandler({ dumpExceptions: true, showStack: true })); // Start up the server on the port specified in the config server.listen(config.server.listenPort, 'localhost', 511, function() { // // Once the server is listening we automatically open up a browser var open = require('open'); open('http://localhost:' + config.server.listenPort + '/'); }); console.log('Deengo Business App Server - listening on port: ' + config.server.listenPort); secureServer.listen(config.server.securePort); console.log('Deengo Business App Server - listening on secure port: ' + config.server.securePort); 

lib / security.js

 var express = require('express'); var passport = require('passport'); var app = express(); var BearerStrategy = require('passport-http-bearer').Strategy var filterUser = function(user) { if ( user ) { return { user : { id: user._id.$oid, email: user.email, firstName: user.firstName, lastName: user.lastName, admin: user.admin } }; } else { return { user: null }; } }; var security = { initialize: function(_authorize_url, _access_token, _apiKey, _secretKey, _scopereq) { passport.use('deengo-auth', new OAuth2Strategy({ authorizationURL: _authorize_url, tokenURL: _access_token, clientID: _apiKey, clientSecret: _secretKey, callbackURL: 'http://localhost:3000/oauth/autorize/callback', scope: _scopereq, passReqToCallback: true, skipUserProfile: true }, function(req, accessToken, refreshToken, profile, done) { client['headers']['authorization'] = 'bearer ' + req.session.passport.accessToken; User.findOrCreate({ clientId: clientId }, function(err, user) { done(err, user); }); } )); }, authenticationRequired: function(req, res, next) { console.log('authRequired'); if (req.isAuthenticated()) { next(); } else { res.json(401, filterUser(req.user)); } }, adminRequired: function(req, res, next) { console.log('adminRequired'); if (req.user && req.user.admin ) { next(); } else { res.json(401, filterUser(req.user)); } }, sendCurrentUser: function(req, res, next) { res.json(200, filterUser(req.user)); res.end(); }, login: function(req, res, next) { console.log(req.body.email); console.log(req.body.password); function authenticationFailed(err, user, info){ //if (err) { return next(err); } /*if (!user) { return res.json(filterUser(user)); } req.logIn(user, function(err) { if ( err ) { return next(err); } return res.json(filterUser(user)); });*/ } //passport.authenticate("deengo-auth", authenticationFailed)(req, res, next); return null; }, logout: function(req, res, next) { req.logout(); res.send(204); } }; module.exports = security; 

lib / DeengoStrategy.js

 var util = require('util'); var passport = require('passport'); var LocalStrategy = require('passport-local').Strategy; var BearerStrategy = require('passport-http-bearer').Strategy; var rest = require('request'); function DeengoRestStrategy(authorize_url, access_token, apiKey, secretKey, scopereq) { this.authorize_url = authorize_url; this.access_token = access_token; this.apiKey = apiKey; this.secretKey = secretKey; this.scopereq = secretKey; this.baseUrl = 'http://localhost:8080/deengo/api/'; // Call the super constructor - passing in our user verification function // We use the email field for the username LocalStrategy.call(this, { usernameField: 'email' }, this.verifyUser.bind(this)); // Serialize the user into a string (id) for storing in the session passport.serializeUser(function(user, done) { done(null, user.id); }); // Deserialize the user from a string (id) into a user (via a cll to REST) passport.deserializeUser(this.get.bind(this)); // We want this strategy to have a nice name for use by passport, eg app.post('/login', passport.authenticate('deengo')); this.name = DeengoRestStrategy.name; } // DeengoRestStrategy inherits from LocalStrategy util.inherits(DeengoRestStrategy, LocalStrategy); DeengoRestStrategy.name = "deengo"; // Query the users collection DeengoRestStrategy.prototype.query = function(query, done) { query.accessToken = this.accessToken; // Add the apiKey to the passed in query var request = rest.get(this.baseUrl, { qs: query, json: {} }, function(err, response, body) { done(err, body); }); }; // Get a user by id DeengoRestStrategy.prototype.get = function(id, done) { var query = { apiKey: this.apiKey }; var request = rest.get(this.baseUrl + id, { qs: query, json: {} }, function(err, response, body) { done(err, body); }); }; // Find a user by their email DeengoRestStrategy.prototype.findByEmail = function(email, done) { this.query({ q: JSON.stringify({email: email}) }, function(err, result) { if ( result && result.length === 1 ) { return done(err, result[0]); } done(err, null); }); }; // Check whether the user passed in is a valid one DeengoRestStrategy.prototype.verifyUser = function(email, password, done) { this.findByEmail(email, function(err, user) { if (!err && user) { if (user.password !== password) { user = null; } } done(err, user); }); }; module.exports = DeengoRestStrategy; 

No sé si tengo que usar el Portador de pasaportes o no y cómo usarlo.

Gracias de antemano por cualquier ayuda.

Saludos,

Eduardo

No sé si tengo que usar el Portador de pasaportes o no y cómo usarlo.

No. Hay otras opciones, tales como:

  • oauth.io

  • httpProvider + express middleware

Aquí hay un ejemplo de cómo usar el pasaporte:

 // Express using passport-local // This code is adaptation of examples/express3 from https://github.com/jaredhanson/passport-local // configure Express app.configure(function() { // ... app.use(express.session({ // The domain should start with a dot, as this allows the subdomain. domain: '.app.local', secret: 'keyboard cat' })); // Enable cors. app.use(function(req, res, next) { res.header('Access-Control-Allow-Credentials', true); res.header('Access-Control-Allow-Origin', req.headers.origin); res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE'); res.header('Access-Control-Allow-Headers', 'X-Requested-With, X-HTTP-Method-Override, Content-Type, Accept'); next(); }); // ... }); app.get('/account', ensureAuthenticated, function(req, res){ // Return the current user's info res.json(req.user); }); 

Referencias

  • Express + AngularJS Subdominio de inicio de sesión