Flask-SqlAlchemy、Bcrypt、Postgres 编码问题
Flask-SqlAlchemy, Bcrypt, Postgres issue with encoding
我正在从头开始编写我的第一个 API,并且有一个 /login 端点在使用 bcrypt 验证用户密码时出错,但仅当使用 Postgres 作为我的数据库时,在使用 SQLite3 时才能正常工作。
此外,我们始终欢迎任何有关更好地构建我的模型或路线的方法的帮助,这是我在 Flask 中的第一个 API / Python 所以我仍在学习。
提前致谢!
错误:
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
[2021-06-22 12:06:14,415] ERROR in app: Exception on /api/v1/login [POST]
Traceback (most recent call last):
File "C:\Users\x4c8\Projects\money_api\venv\lib\site-packages\flask\app.py", line 2070, in wsgi_app
response = self.full_dispatch_request()
File "C:\Users\x4c8\Projects\money_api\venv\lib\site-packages\flask\app.py", line 1515, in full_dispatch_request
rv = self.handle_user_exception(e)
File "C:\Users\x4c8\Projects\money_api\venv\lib\site-packages\flask\app.py", line 1513, in full_dispatch_request
rv = self.dispatch_request()
File "C:\Users\x4c8\Projects\money_api\venv\lib\site-packages\flask\app.py", line 1499, in dispatch_request
return self.ensure_sync(self.view_functions[rule.endpoint])(**req.view_args)
File "C:\Users\x4c8\Projects\money_api\routes.py", line 47, in token_get
check = user.verify_password(password)
File "C:\Users\x4c8\Projects\money_api\models.py", line 40, in verify_password
return bcrypt.checkpw(enc_pw, self.password_hash)
File "C:\Users\x4c8\Projects\money_api\venv\lib\site-packages\bcrypt\__init__.py", line 120, in checkpw
raise TypeError("Unicode-objects must be encoded before checking")
TypeError: Unicode-objects must be encoded before checking
127.0.0.1 - - [22/Jun/2021 12:06:14] "POST /api/v1/login HTTP/1.1" 500 -
Models.py 中的用户 class:
class User(db.Model, Serializer):
__tablename__ = 'user'
id = db.Column(db.Integer, primary_key=True)
first_name = db.Column(db.String(15), unique=False, nullable=True)
last_name = db.Column(db.String(20), unique=False, nullable=True)
email = db.Column(db.String(120), unique=True, nullable=False)
password_hash = db.Column(db.String(255), unique=False, nullable=False)
country = db.Column(db.String(2), unique=False, nullable=True)
subscription_level = db.Column(db.Integer, default=0)
subscription_purchase_date = db.Column(db.DateTime(), unique=False, nullable=True)
last_login = db.Column(db.DateTime(), unique=False, default=datetime.utcnow)
modified_at = db.Column(db.DateTime(), unique=False, default=datetime.utcnow)
created_at = db.Column(db.DateTime(), unique=False, default=datetime.utcnow)
# relationships
portfolios = db.relationship('StockPortfolio', foreign_keys='StockPortfolio.fk_user', backref='user',
lazy='dynamic', cascade='all, delete-orphan')
@property
def password(self):
raise AttributeError('password not readable')
@password.setter
def password(self, password):
enc_pw = password.encode('utf-8')
self.password_hash = bcrypt.hashpw(enc_pw, bcrypt.gensalt()).decode('utf-8')
def verify_password(self, password):
enc_pw = password.encode('utf-8')
return bcrypt.checkpw(enc_pw, self.password_hash)
def serialize(self):
d = Serializer.serialize(self)
del d['password_hash']
del d['modified_at']
del d['created_at']
del d['last_login']
return d
/从 routes.py
登录
# POST /login
@routes.route(api_v1 + 'login', methods=['POST'])
def token_get():
if request.method == 'POST':
body = request.get_json()
# fail on missing params
if body.get('email') is None:
return jsonify(msg='email parameter is missing'), 422
if body.get('password') is None:
return jsonify(msg='password parameter is missing'), 422
# fail on email not in use
user = User.query.filter_by(email=body.get('email')).first()
if user is None:
return jsonify(msg='Email is not in use'), 404
else:
password = body.get('password')
check = user.verify_password(password)
if check:
# record last login
user.last_login = datetime.utcnow()
# prep and return tokens
access_token = create_access_token(identity=user.id)
refresh_token = create_refresh_token(identity=user.id)
return jsonify(msg='login successful', access_token=access_token, refresh_token=refresh_token), 200
else:
return jsonify(msg='incorrect email or password'), 409
您只需更改这部分代码即可将 password_hash
转换为字节:
def verify_password(self, password):
enc_pw = password.encode('utf-8')
return bcrypt.checkpw(enc_pw, bytes(self.password_hash, 'utf-8'))
我正在从头开始编写我的第一个 API,并且有一个 /login 端点在使用 bcrypt 验证用户密码时出错,但仅当使用 Postgres 作为我的数据库时,在使用 SQLite3 时才能正常工作。
此外,我们始终欢迎任何有关更好地构建我的模型或路线的方法的帮助,这是我在 Flask 中的第一个 API / Python 所以我仍在学习。
提前致谢!
错误:
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
[2021-06-22 12:06:14,415] ERROR in app: Exception on /api/v1/login [POST]
Traceback (most recent call last):
File "C:\Users\x4c8\Projects\money_api\venv\lib\site-packages\flask\app.py", line 2070, in wsgi_app
response = self.full_dispatch_request()
File "C:\Users\x4c8\Projects\money_api\venv\lib\site-packages\flask\app.py", line 1515, in full_dispatch_request
rv = self.handle_user_exception(e)
File "C:\Users\x4c8\Projects\money_api\venv\lib\site-packages\flask\app.py", line 1513, in full_dispatch_request
rv = self.dispatch_request()
File "C:\Users\x4c8\Projects\money_api\venv\lib\site-packages\flask\app.py", line 1499, in dispatch_request
return self.ensure_sync(self.view_functions[rule.endpoint])(**req.view_args)
File "C:\Users\x4c8\Projects\money_api\routes.py", line 47, in token_get
check = user.verify_password(password)
File "C:\Users\x4c8\Projects\money_api\models.py", line 40, in verify_password
return bcrypt.checkpw(enc_pw, self.password_hash)
File "C:\Users\x4c8\Projects\money_api\venv\lib\site-packages\bcrypt\__init__.py", line 120, in checkpw
raise TypeError("Unicode-objects must be encoded before checking")
TypeError: Unicode-objects must be encoded before checking
127.0.0.1 - - [22/Jun/2021 12:06:14] "POST /api/v1/login HTTP/1.1" 500 -
Models.py 中的用户 class:
class User(db.Model, Serializer):
__tablename__ = 'user'
id = db.Column(db.Integer, primary_key=True)
first_name = db.Column(db.String(15), unique=False, nullable=True)
last_name = db.Column(db.String(20), unique=False, nullable=True)
email = db.Column(db.String(120), unique=True, nullable=False)
password_hash = db.Column(db.String(255), unique=False, nullable=False)
country = db.Column(db.String(2), unique=False, nullable=True)
subscription_level = db.Column(db.Integer, default=0)
subscription_purchase_date = db.Column(db.DateTime(), unique=False, nullable=True)
last_login = db.Column(db.DateTime(), unique=False, default=datetime.utcnow)
modified_at = db.Column(db.DateTime(), unique=False, default=datetime.utcnow)
created_at = db.Column(db.DateTime(), unique=False, default=datetime.utcnow)
# relationships
portfolios = db.relationship('StockPortfolio', foreign_keys='StockPortfolio.fk_user', backref='user',
lazy='dynamic', cascade='all, delete-orphan')
@property
def password(self):
raise AttributeError('password not readable')
@password.setter
def password(self, password):
enc_pw = password.encode('utf-8')
self.password_hash = bcrypt.hashpw(enc_pw, bcrypt.gensalt()).decode('utf-8')
def verify_password(self, password):
enc_pw = password.encode('utf-8')
return bcrypt.checkpw(enc_pw, self.password_hash)
def serialize(self):
d = Serializer.serialize(self)
del d['password_hash']
del d['modified_at']
del d['created_at']
del d['last_login']
return d
/从 routes.py
登录# POST /login
@routes.route(api_v1 + 'login', methods=['POST'])
def token_get():
if request.method == 'POST':
body = request.get_json()
# fail on missing params
if body.get('email') is None:
return jsonify(msg='email parameter is missing'), 422
if body.get('password') is None:
return jsonify(msg='password parameter is missing'), 422
# fail on email not in use
user = User.query.filter_by(email=body.get('email')).first()
if user is None:
return jsonify(msg='Email is not in use'), 404
else:
password = body.get('password')
check = user.verify_password(password)
if check:
# record last login
user.last_login = datetime.utcnow()
# prep and return tokens
access_token = create_access_token(identity=user.id)
refresh_token = create_refresh_token(identity=user.id)
return jsonify(msg='login successful', access_token=access_token, refresh_token=refresh_token), 200
else:
return jsonify(msg='incorrect email or password'), 409
您只需更改这部分代码即可将 password_hash
转换为字节:
def verify_password(self, password):
enc_pw = password.encode('utf-8')
return bcrypt.checkpw(enc_pw, bytes(self.password_hash, 'utf-8'))