向Mean.io初学者解释Mean.io示例包的身份验证工作原理。

10

我正在学习 mean.io,通过这个教程视频(链接),它展示了一个例子包(由mean package mymodule创建)。文档中也有描述,可在“Packages”下找到(链接)。我需要帮助理解所给的认证/授权如何工作。

默认的样本包/模块具有简单的用户身份验证,在客户端上:

myapp/packages/mymodule/public/views/index.html 包含:

    <li>
      <a href="mymodule/example/anyone">Server route that anyone can access</a>
    </li>
    <li>
      <a href="mymodule/example/auth">Server route that requires authentication</a>
    </li>
    <li>
      <a href="mymodule/example/admin">Server route that requires admin user</a>
    </li>

在服务器端,

myapp/packages/mymodule/server/routes/mymodule.js,包含:

// The Package is past automatically as first parameter
module.exports = function(Mymodule, app, auth, database) {

  app.get('/mymodule/example/anyone', function(req, res, next) {
    res.send('Anyone can access this');
  });

  app.get('/mymodule/example/auth', auth.requiresLogin, function(req, res, next) {
    res.send('Only authenticated users can access this');
  });

  app.get('/mymodule/example/admin', auth.requiresAdmin, function(req, res, next) {
    res.send('Only users with Admin role can access this');
  });

  ...
};

不同身份验证的魔法取决于app.get()的第二个参数,带有额外的身份验证回调:无、auth.requiresLoginauth.requiresAdmin

这就是身份验证的魔法(也可以在github上找到):

myapp/packages/access/server/config/authorization.js

/**
 * Generic require login routing middleware
 */
exports.requiresLogin = function(req, res, next) {
  if (!req.isAuthenticated()) {
    return res.send(401, 'User is not authorized');
  }
  next();
};

/**
 * Generic require Admin routing middleware
 * Basic Role checking - future release with full permission system
 */
exports.requiresAdmin = function(req, res, next) {
  if (!req.isAuthenticated() || !req.user.hasRole('admin')) {
    return res.send(401, 'User is not authorized');
  }
  next();
};

问题A:为什么在authorization.js中使用"exports.requiresLogin"和"exports.requiresAdmin",而不是使用"somethingelse.requiresLogin"和"somethingelse.requiresAdmin"?这个"exports"与myapp/packages/access/server/config/passport.jsexports有关吗:module.exports = function(passport) { ...}github?如果是,我们在什么情况下可以使用这个"exports"?


由于认证授权规则是在"access"包中编写并在"mymodule"中使用,因此Mean.io包之间不是独立的。 "Access"包在

myapp/packages/access/app.js, github上注册:

var mean = require('meanio'),
  Module = mean.Module,
  passport = require('passport');

var Access = new Module('access');

Access.register(function(database) {

  // Register auth dependency

  var auth = require('./server/config/authorization');
  require('./server/config/passport')(passport);

  // This is for backwards compatibility
  mean.register('auth', function() {
    return auth;
  });

  mean.register('passport', function() {
    return passport;
  });

  Access.passport = passport;
  Access.middleware = auth;

  return Access;
});

问题 B:Mean.io是否自动链接所有的包,还是需要某些代码来链接包?是由于下面显示的“这是为了向后兼容性”而链接吗?如果是这样,那么“auth”在哪里可以使用?所有的包都在myapp/packages/目录下吗?那么在mean.io基本应用程序目录myapp/中如何处理?

var auth = require('./server/config/authorization');

// This is for backwards compatibility
  mean.register('auth', function() {
    return auth;
  });
问题C:为什么是“Access.passport = passport;”,而不是把“Access.middleware = auth;”改为“Access.auth = auth”会发生什么?

就“exports”而言,它是Node模块系统的一部分。每当您“require”某些内容时,您将从所需文件中获取“exports”对象。 - ivarni
有关问题A,请参见https://dev59.com/12435IYBdhLWcg3wnBd8 - Steve Jansen
1个回答

1

关于问题A(关于使用exports)的说明

在Node.js中,将值分配给exports对象使这些值可供需要源文件的require代码使用。

例如,给定文件foo.js

exports.foo = "FOO";
exports.bar = "BAR";

和文件 main.js

var foo = require('foo.js');
console.log('foo=',foo.foo,'; bar=',foo.bar);

运行 node main.js 将输出 foo= FOO ; bar= BAR

例如,参见 Node 的模块文档这篇关于 requireexports 的文章

关于问题 B(关于“链接”包)

这个问题的答案是对问题 A 答案的补充。

有一些代码可以“链接”包。它就是 require 语句。

在你的 app.js 源代码中,第一行(读取 var mean = require('meanio'))将把本地变量 mean 设置为在加载 meanio.js 和/或 meanio 模块时分配给 exports 对象的任何值。

passport = require('passport') 相同。在这种情况下,当加载 passport 模块的 index.js 时,本地变量 passport 将等于 exports 的值。

关于问题 C

我不完全确定你在问什么,但让我试着回答一下。

在这种情况下:

1)第 1 行的 var mean = require('meanio') “导入”了 meanio 模块,因此本地变量 mean 或多或少地被设置为 meanio 模块中 exports 的值。

2)第 2 行的 Module = mean.Module 将本地变量 Module 设置为 mean.Module 的值,mean.Module 必须已经在 meanio 模块中被赋值。

3)var Access = new Module('access') 实例化 Module 类的一个实例,并将其分配给本地变量 Access

4) Access.passport = passportpassport 模块(在第3行中 require 的值)的实例变量赋值给名为 Accessmeanio.Module 实例内部的名为 passport 的实例变量。

5) Access.middleware = auth./server/config/authorization 中返回的值分配给名为 middleward 的实例变量,该实例变量位于名为 Accessmeanio.Module 实例内部。

我不熟悉 "meanio" 模块,但根据此代码,看起来您正在配置名为 Accessmeanio.Module("access") 实例,通过分配特定的 "magic" 变量名。

换句话说,您可以使用 Access.setPassport(passport); Access.setMiddleware(auth) 或者(而不是第5行)var Access = new Module('access',passport,auth),而不是使用 Access.passport = passport; Access.middleware = auth

也就是说,“meanio”模块的作者似乎决定使用特殊的变量名来配置类,而不是“setter”方法或传递给构造函数的参数。我假设在meanio代码中的某个地方,你会找到对诸如this.middlewarethis.passport之类的东西的引用,其中代码假定您已经像在代码示例的最后几行发生的那样“填充”了这些实例变量。
如果您添加了Access.auth = auth,那么所有发生的只是Access对象将具有一个新的属性名为auth,其等于局部变量auth的值。
如果您使用Access.auth代替Access.middleware,我假设Access类中使用this.middleware的任何代码都将失败,因为从未为Access.middleware分配任何值,而Access.auth不是meanio正在寻找的“魔术”变量名称之一。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接