web-dev-qa-db-ja.com

ループバックでパスワード変更を実装する

Loopbackの組み込みメソッドを使用してパスワード変更機能を実装しようとしています。正常に機能しますが、パスワードをhashで更新せず、プレーンテキストをデータベースに保存するだけです。私は使っている loopback-component-passportこのプロジェクトのnpmパッケージ。多くのサイトを検索しましたが、この機能を実装する適切な方法を見つけることができません。誰かがこれを行う方法を知っていますか?

//Change user's pasword
app.post('/change-password', function(req, res, next) {
  var User = app.models.user;
  if (!req.accessToken) return res.sendStatus(401);
  //verify passwords match
  if (!req.body.password || !req.body.confirmation ||
    req.body.password !== req.body.confirmation) {
    return res.sendStatus(400, new Error('Passwords do not match'));
  }

  User.findById(req.accessToken.userId, function(err, user) {
    if (err) return res.sendStatus(404);
    user.hasPassword(req.body.oldPassword, function(err, isMatch) {
      if (!isMatch) {
        return res.sendStatus(401);
      } else {
        user.updateAttribute('password', req.body.password, function(err, user) {
          if (err) return res.sendStatus(404);
          console.log('> password change request processed successfully');
          res.status(200).json({msg: 'password change request processed successfully'});
        });
      }
    });
  });
});
11
Vicky Gonsalves

組み込みを使用 User.hashPassword ソースコードで見られる

//Hash the plain password
user.updateAttribute('password', User.hashPassword(req.body.password), function(err, user) {
    ...
});
14

これは実際には、loopback-datasource-juggler2.45.0で導入されたバグです。パスワードはデフォルトでハッシュされている必要があります。

https://github.com/strongloop/loopback-datasource-juggler/issues/844

https://github.com/strongloop/loopback/issues/2029

したがって、user.hashpasswordを使用する場合は、正しく行われなかった場合にすでにハッシュされたpwをハッシュする可能性があるため、これが修正されると将来のバージョンで機能しない可能性があることに注意してください。ただし、長さのチェックと$ 2 $のチェックがすでにあるはずです。ハッシュ値の開始ビットが何であれ。

Edit:loopback-datasource-jugglerの2.45.1をインストールすると、修正されるはずです。

4
Brian

これは、特定のupdatePasswordリモートメソッドをLoopBack/StrongLoop-IBMプロジェクトに実装するための私の「完全な」ソリューションです。 loopback-datasource-jugglerパッケージのバージョンは2.45.1(npm list loopback-datasource-juggler)。私のユーザーモデルはMyUserModelと呼ばれ、組み込みモデルUserから継承します。

「my-user-model.js」

module.exports = function (MyUserModel) {

...

MyUserModel.updatePassword = function (ctx, emailVerify, oldPassword, newPassword, cb) {
  var newErrMsg, newErr;
  try {
    this.findOne({where: {id: ctx.req.accessToken.userId, email: emailVerify}}, function (err, user) {
      if (err) {
        cb(err);
      } else if (!user) {
        newErrMsg = "No match between provided current logged user and email";
        newErr = new Error(newErrMsg);
        newErr.statusCode = 401;
        newErr.code = 'LOGIN_FAILED_EMAIL';
        cb(newErr);
      } else {
        user.hasPassword(oldPassword, function (err, isMatch) {
          if (isMatch) {

            // TODO ...further verifications should be done here (e.g. non-empty new password, complex enough password etc.)...

            user.updateAttributes({'password': newPassword}, function (err, instance) {
              if (err) {
                cb(err);
              } else {
                cb(null, true);
              }
            });
          } else {
            newErrMsg = 'User specified wrong current password !';
            newErr = new Error(newErrMsg);
            newErr.statusCode = 401;
            newErr.code = 'LOGIN_FAILED_PWD';
            return cb(newErr);
          }
        });
      }
    });
  } catch (err) {
    logger.error(err);
    cb(err);
  }
};

MyUserModel.remoteMethod(
  'updatePassword',
  {
    description: "Allows a logged user to change his/her password.",
    http: {verb: 'put'},
    accepts: [
      {arg: 'ctx', type: 'object', http: {source: 'context'}},
      {arg: 'emailVerify', type: 'string', required: true, description: "The user email, just for verification"},
      {arg: 'oldPassword', type: 'string', required: true, description: "The user old password"},
      {arg: 'newPassword', type: 'string', required: true, description: "The user NEW password"}
    ],
    returns: {arg: 'passwordChange', type: 'boolean'}
  }
);

...
};

「my-user-model.json」

{
   "name": "MyUserModel",
   "base": "User",

   ...

   "acls": [
     ...
     {
       "comment":"allow authenticated users to change their password",
       "accessType": "EXECUTE",
       "property":"updatePassword",
       "principalType": "ROLE",
       "principalId": "$authenticated",
       "permission": "ALLOW"
     }
   ...
   ],
   ...
}

注意:MyUserModelでPUTリクエストを使用し、本文に{"password": "... newpassword ..."}を指定するだけで、同じ機能を実行できます。ただし、新しいパスワードにセキュリティポリシーを適用するには、このトリックよりも特定のリモートメソッドを使用する方が便利な場合があります。

1
Franck