【问题标题】:using bcrypt password hashing for user authentication使用 bcrypt 密码散列进行用户身份验证
【发布时间】:2016-12-22 12:48:02
【问题描述】:

我正在尝试在我的应用中使用散列密码,如下所示:

class UserService():

    def register_user(self, username, email, password):
        if self.__checkIfUserExists(username) is True:
            return False
        else:

            hashed_password = self.__hash_password(password.encode('utf-8'), bcrypt.gensalt())

            user = User(username=username, email=email, password_hash=hashed_password)

            db.session.add(user)
            db.session.commit()
            db.session.close()

        return True

    def authenticate_user(self, email, password):
        user = User.query.filter_by(email=email).first()
        hashed_pw = self.__hash_password(password.encode("utf-8"), bcrypt.gensalt())
        print(hashed_pw == user.password_hash)
        if user and hashed_pw == user.password_hash:
            return True
        return False


    def __checkIfUserExists(self, username):
        exists = db.session.query(db.exists().where(User.username== username)).scalar()
        return exists

    def __hash_password(self, password, salt):
        return bcrypt.hashpw(password, salt)

嗯,密码永远不会匹配。

如何让它工作?我的错误在哪里?我以为我必须将提供的密码的哈希值与存储在数据库中的哈希值进行比较..?

【问题讨论】:

    标签: python flask bcrypt


    【解决方案1】:

    来自https://pypi.python.org/pypi/bcrypt/2.0.0

    >>> import bcrypt
    >>> password = b"super secret password"
    >>> # Hash a password for the first time, with a randomly-generated salt
    >>> hashed = bcrypt.hashpw(password, bcrypt.gensalt())
    >>> # Check that a unhashed password matches one that has previously been
    >>> #   hashed
    >>> if bcrypt.hashpw(password, hashed) == hashed:
    ...     print("It Matches!")
    ... else:
    ...     print("It Does not Match :(")
    

    请注意,hashpw 接受盐或以前散列的密码(包括用于创建它的盐),以便进行适当的比较。

    您已经使用了两次bcrypt.gensalt(),这会创建两个不同的随机盐,因此哈希值会有所不同。

    【讨论】:

    • aah.... 它使用散列密码。该死的人……应该看到的。不过还是谢谢!!
    【解决方案2】:

    Alex 是对的,第二次添加 gensalt 是个问题。但是您不必再次计算哈希。

    从 3.1.0 版本开始,添加了 checkpw。

    为了让它保持 Python 风格,您可以使用 checkpw 而不是再次与散列密码进行比较。

    >>> import bcrypt
    >>> password= 'cantguessme'
    >>>hashed= bcrypt.hashpw(password.encode('utf-8'), bcrypt.gensalt(12))
    >>>if bcrypt.checkpw(password, hashed):
       ...     print("Yaay, It Matches!")
       ... else:
       ...     print("Oops, It Does not Match :(")
    

    【讨论】:

      【解决方案3】:

      此答案可能会帮助使用 DB 保存加密密码的人。

      问题:我将编码后的密码保存到字符串列。

      解决方案:哈希密码是二进制类型,必须保存为二进制而不是字符串或JSON。

      我的代码中密码列的列属性,我在这里使用了 Postgresql、Flask 和 sqlalchemy,它们在我更改列数据类型后起作用

      from sqlalchemy import Column, String, Integer, Boolean, Date, LargeBinary
      from db import Base
      
      class User(Base):
          __tablename__ = 'users'
      
          id = Column(Integer, primary_key=True, autoincrement=True)
          userId = Column(String(50), nullable=False)
          firstName = Column(String(50), nullable=False)
          password = Column(LargeBinary(100), nullable=False)
          recovery = Column(String(25))
          phone = Column(String(10), nullable=False, unique=True)
          phoneVerified = Column(Boolean, nullable=False)
          email = Column(String(50), nullable=False, unique=True)
          emailVerified = Column(Boolean, nullable=False)
      
          def __init__(self, userId, firstName, password, phone, phoneVerified, email, emailVerified, recovery):
              self.userId = userId
              self.firstName = firstName
              self.password = password
              self.phone = phone
              self.email = email
              self.phoneVerified = phoneVerified
              self.emailVerified = emailVerified
              self.recovery = recovery
      

      资源代码:

      import bcrypt
      import shortuuid
      from flask_restful import Resource, reqparse
      from entities.User import User
      
      class Register(Resource):
          @staticmethod
          def post():
              data = Register.parser.parse_args()
              hashed = bcrypt.hashpw(data.password.encode('utf-8'), bcrypt.gensalt())
      
              user = User(userId=shortuuid.ShortUUID().random(length=10), firstName=data.firstName,
                                          password=hashed, phone=data.phone, phoneVerified=False, email=data.email,
                                          emailVerified=False, recovery=shortuuid.ShortUUID().random(length=25))
              session.add(user)
              session.commit()
              session.close()
              return {'description': 'You are registered'}, 201
              
      
      class Login(Resource):
          @staticmethod
          def post():
              data = Login.parser.parse_args()
              user = find_by_email(data.email)
              if user:
                  pw_check = bcrypt.checkpw(password=data.password.encode('utf-8'), hashed_password=user.password)
                  access_token = create_access_token(identity=user.id, fresh=True)
                  refresh_token = create_refresh_token(identity=user.id)
                  return {'access_token': access_token, 'refresh_token': refresh_token}, 200
              return {'description': 'Invalid credentials'}, 401
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-06-06
        • 2014-12-29
        • 2021-06-04
        • 1970-01-01
        • 2016-07-15
        • 1970-01-01
        • 2020-02-28
        • 2017-04-25
        相关资源
        最近更新 更多