2

我正在为应用程序进行Auth0集成。我有一个现有的应用程序,它使用 ASP.NET Core Identity 和一个 SQL 数据库,目前带有常用表(AspNetUsers、AspNetRoles 等)。

问题是 Auth0 当前具有自定义数据库模板,用于与 ASP.NET Membership Provider(MVC3 Universal Providers 和 MVC4 Simple Membership)数据库一起使用,但没有 ASP.NET Core Identity。由于我不确切知道如何编写与我的 ASP.NET Core 身份数据库兼容所需的密码哈希,这是一个大问题。

有没有人有使用现有 ASP.NET Core Identity 数据库的 Auth0 自定义数据库脚本示例?或者,至少是用于自己编码的散列算法?

有关详细信息,ASP.NET Core Identity 数据库有一个AspNetUsers表,其中包含此集成感兴趣的以下列:

  • Id(PK,nvarchar,不为空)
  • Email(nvarchar,空)
  • PasswordHash(nvarchar,空)
  • SecurityStamp(nvarchar,空)
  • UserName(nvarchar,不为空)

为了清楚起见,我问的是如何在用 JavaScript 编写的 Auth0 配置中设置自定义数据库脚本;不是 ASP.NET Web 应用程序代码。根据文档进行设置,Web 应用程序非常简单。只是 Auth0 内置自定义数据库模板不包含用于 ASP.NET Core Identity 数据库架构和密码哈希的示例。

任何帮助将不胜感激!

4

1 回答 1

3

您需要弄清楚使用的散列算法并修改模板中的脚本,也需要使用 Auth0 文档,以使其正确。您可以在aspnet-identity-pw项目中找到该算法的代码。

下面是 Auth0 的示例登录数据库操作脚本,它与存储在 Azure SQL 数据库中的 ASP.NET Core Identity 2.0 数据库一起使用:

function login (username, password, callback) {

  var Connection = require('tedious@1.11.0').Connection;
  var Request = require('tedious@1.11.0').Request;
  var TYPES = require('tedious@1.11.0').TYPES;

  var connection = new Connection({
    userName:  configuration.db_username + '@' + configuration.db_server,
    password:  configuration.db_password,
    server:    configuration.db_server, //'dbserver.database.windows.net',
    options: {
      database:  configuration.db_database,
      encrypt: true
    }
  });

  connection.on('debug', function(text) {
    // if you have connection issues, uncomment this to get more detailed info
    //console.log(text);
  }).on('errorMessage', function(text) {
    // this will show any errors when connecting to the SQL database or with the SQL statements
    //console.log(JSON.stringify(text));
  });

  connection.on('connect', function (err) {
    if (err) {
      console.log('error: ' + JSON.stringify(err));
      return callback(err);
    }

    getMembershipUser(username, function(err, user) {
      if (err) {
        return callback(err); // this will return a 500
      }
      if (!user.profile) {
        return callback(); // this will return a 401
      }

      validatePassword(password, user.password.hash, function(err, isValid) {
        if (!isValid) {
          return callback(); // unauthorized
        }

        callback(null, user.profile);
      });

    });
  });


  // Membership Provider implementation used with ASP.NET Core Identity database

  /**
   * getMembershipUser
   *
   * This function gets a username or email and returns a user info, password hashes and salt
   *
   * @usernameOrEamil   {[string]}    the username or email, the method will do a query
   *                                  on both with an OR
   * @callback          {[Function]}  first argument will be the Error if any, and second
   *                                  argument will be a user object
   */
  function getMembershipUser(usernameOrEmail, callback) {
    var user = {};
    var query =
      'SELECT Id, UserName, Email, PasswordHash, SecurityStamp from AspNetUsers ' +
      'WHERE UserName = @UserName';

    var getMembershipQuery = new Request(query);

    getMembershipQuery.addParameter('UserName', TYPES.VarChar, usernameOrEmail);

    getMembershipQuery.on('row', function (fields) {
      user.profile = {};
      user.password = {};
      for(var f in fields) {
        var item = fields[f];
        if (item.metadata.colName === 'Id') {
          user.profile.user_id = item.value;
        } else if (item.metadata.colName === 'UserName') {
          user.profile.nickname = item.value;
        } else if (item.metadata.colName ==='Email') {
          user.profile.email = item.value;
        } else if (item.metadata.colName ==='PasswordHash') {
          user.password.hash = item.value;
        }
      }

      //console.log('User: ' + JSON.stringify(user));
      callback(null, user);
    });

    connection.execSql(getMembershipQuery);
  }

  /**
   * validatePassword
   *
   * This function gets the password entered by the user, and the original password
   * hash and salt from database and performs an HMAC SHA256 hash.
   *
   * @password      {[string]}      the password entered by the user
   * @originalHash  {[string]}      the original password hashed from the database
   *                                (including the salt).
   * @return        {[bool]}        true if password validates
   */
  function validatePassword(password, originalHash, callback) {
    aspnet_identity_pw.validatePassword(password, originalHash, function(result, isValid) {
      console.log('Is Password Valid: ' + isValid);

      callback(null, isValid);
    });
  }

  var aspnet_identity_pw = {
    validatePassword: function(password, hashedPassword, callback) {
      // Original Source:
      //   https://github.com/Syncbak-Git/aspnet-identity-pw/blob/master/lib/aspnet-identity-pw.js
      //   https://www.npmjs.com/package/aspnet-identity-pw
      //   There were some slight modifications to make it run well in Auth0

      var done = false;
      var error = null;
      var result = null;

      if(!hashedPassword) {

          if(callback) {
              callback(null, false);
          }

          return false;
      }

      if(!password) {

          error = new Error("Password is required.");

          if(callback) {
              callback(error);
              return;
          }

          throw error;
      }

      var src = new Buffer(hashedPassword, 'base64');

      if(src.length !== 49 || src[0] !== 0) {
          return false;
      }

      var salt = new Buffer(16);
      src.copy(salt, 0, 1, 17);

      var bytes = new Buffer(32);
      src.copy(bytes, 0, 17, 49);

      var hashed = crypto.pbkdf2Sync(password, salt, 1000, 32, 'sha1');
      result = true;

          for(var i = 0; i < 32; i++) {
              if(bytes[i] !== hashed[i]) {
                  result = false;
                  break;
              }
          }

          done = true;

          if(callback) {
              callback(null, result);
          }

      if(!callback) {
        throw 'callback required!';
      }

      }
  };

  }

这似乎永远地被完全弄清楚了。尤其是要对密码哈希算法进行编码,直到偶然发现列出了它的代码的 js 项目。

希望这对其他人有帮助!

于 2018-11-01T22:56:25.400 回答