문제

I'm reading code from https://github.com/FrankHassanabad/Oauth2orizeRecipes which demonstrate the use of OAuth2orize, which can be used to implement OAuth2 authorization server.

The question I'm asking is nothing fancy though. I just have trouble with the basics of Express 3.x.

In app.js:

oauth2 = require('./oauth2')
. . . 
app.get('/dialog/authorize', oauth2.authorization);

In Oauth2.js:

exports.authorization = [ 
    login.ensureLoggedIn(),
    server.authorization(function (clientID, redirectURI, scope, done) {
        db.clients.findByClientId(clientID, function (err, client) {
            if (err) {
                return done(err);
            }   
            if(client) {
                client.scope = scope;
            }   
            // WARNING: For security purposes, it is highly advisable to check that
            //          redirectURI provided by the client matches one registered with
            //          the server.  For simplicity, this example does not.  You have
            //          been warned.
            return done(null, client, redirectURI);
        }); 
    }), 
    function (req, res, next) {
        //Render the decision dialog if the client isn't a trusted client
        //TODO Make a mechanism so that if this isn't a trusted client, the user can recorded that they have consented
        //but also make a mechanism so that if the user revokes access to any of the clients then they will have to
        //re-consent.
        db.clients.findByClientId(req.query.client_id, function(err, client) {
            if(!err && client && client.trustedClient && client.trustedClient === true) {
                //This is how we short call the decision like the dialog below does
                server.decision({loadTransaction: false}, function(req, callback) {
                    callback(null, { allow: true }); 
                })(req, res, next);
            } else {
                res.render('dialog', { transactionID: req.oauth2.transactionID, user: req.user, client: req.oauth2.client }); 
            }
        });
    }   
];

So, is it because app.get() can take an array of middlewares? I'm trying to find where the code to app.get() is to figure out but I can't find it.

EDIT: I'm on Express 3.6. So according to Infer-on's answer, correct me if I'm wrong. You mean oauth2.authorization array instead of module?

app.VERB goes to this._router[method].apply(this._router, arguments);

where arguments is an array-like object with exactly one item, which is the oauth2.authorization array.

Then goes to router/index.js in the function defined by:

methods.forEach(function(method){
  Router.prototype[method] = function(path){
    var args = [method].concat([].slice.call(arguments));
    this.route.apply(this, args);
    return this;
  };  
});

Here, what previously was arguments is now path. And then becomes args. So the original array given by oauth2.authorization is still there and is an item inside args which has the length of 2, the first item is the method name "get" and the second is the array.

this.route is defined in the same file:

Router.prototype.route = function(method, path, callbacks){
  var method = method.toLowerCase()
    , callbacks = utils.flatten([].slice.call(arguments, 2));

  // ensure path was given
  if (!path) throw new Error('Router#' + method + '() requires a path');

  // ensure all callbacks are functions
  callbacks.forEach(function(fn){
    if ('function' == typeof fn) return;
    var type = {}.toString.call(fn);
    var msg = '.' + method + '() requires callback functions but got a ' + type;
    throw new Error(msg);
  }); 

  // create the route
  debug('defined %s %s', method, path);
  var route = new Route(method, path, callbacks, {
    sensitive: this.caseSensitive,
    strict: this.strict
  }); 

  // add it
  (this.map[method] = this.map[method] || []).push(route);
  return this;
};

Since there is utils.flatten([].slice.call(arguments, 2)); the array from oauth2.authorization gets flattened. So it's as if the things sent weren't array but normal arguments. (I don't know what the "2" is doing). The 3rd of the oauth2.authorization is the callback that's easy to understand. The first is login.ensureLoggedIn() which is a middleware? The second is server.authorization()..but I'm not entirely sure what it's doing.

도움이 되었습니까?

해결책

for the get method, after the first argument, application will add the route, then will pass the other arguments to related controller

this._router[method].apply(this._router, arguments);

app.js

app.get('/', routes.index);

index.js

// controller
exports.index = function(req, res){
  res.render('index', { title: 'Express' });
};

application.js

methods.forEach(function(method){
  app[method] = function(path){
    if ('get' == method && 1 == arguments.length) return this.set(path);

    // deprecated
    if (Array.isArray(path)) {
      console.trace('passing an array to app.VERB() is deprecated and will be removed in 4.0');
    }

    // if no router attached yet, attach the router
    if (!this._usedRouter) this.use(this.router);

    // setup route
    this._router[method].apply(this._router, arguments);
    return this;
  };
});

so

app.get('/dialog/authorize', oauth2.authorization);

for the /dialog/authorize view will be passed the authorization method exported by oauth2.authorization module

EDIT

I'm not sure of the array export, try something like Implement Authorization Endpoint:

app.get('/dialog/authorize',
  login.ensureLoggedIn(),
    server.authorization(function (clientID, redirectURI, scope, done) {
        db.clients.findByClientId(clientID, function (err, client) {
            if (err) {
                return done(err);
            }   
            if(client) {
                client.scope = scope;
            }   
            // WARNING: For security purposes, it is highly advisable to check that
            //          redirectURI provided by the client matches one registered with
            //          the server.  For simplicity, this example does not.  You have
            //          been warned.
            return done(null, client, redirectURI);
        }); 
    }), 
    function (req, res, next) {
        //Render the decision dialog if the client isn't a trusted client
        //TODO Make a mechanism so that if this isn't a trusted client, the user can recorded that they have consented
        //but also make a mechanism so that if the user revokes access to any of the clients then they will have to
        //re-consent.
        db.clients.findByClientId(req.query.client_id, function(err, client) {
            if(!err && client && client.trustedClient && client.trustedClient === true) {
                //This is how we short call the decision like the dialog below does
                server.decision({loadTransaction: false}, function(req, callback) {
                    callback(null, { allow: true }); 
                })(req, res, next);
            } else {
                res.render('dialog', { transactionID: req.oauth2.transactionID, user: req.user, client: req.oauth2.client }); 
            }
        });
    });
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top