PyMongo无需用户名访问哈希token实现登录校验的方法咨询
问题原因
你代码运行失败是由4个核心错误导致的:
- 变量名错误:你定义的集合变量是
tokens_collection,但查询时错误使用了未定义的tokens变量,会直接抛出异常 - 查询逻辑错误:库中存储的是bcrypt哈希后的token值,而你直接用用户提交的明文token作为查询条件。bcrypt哈希会自动添加随机盐,相同明文每次生成的哈希值完全不同,所以永远查不到匹配的文档,
user_login始终为None - 字段名不一致:查询时用的键是
tokens,后续取值用的是user_login['token'],单复数不匹配,就算查到也会报KeyError - 编码缺失:bcrypt比对要求两个参数都是字节类型,你没有对库中取出的哈希字符串做utf-8编码转换,会触发类型错误
解决方案
bcrypt是单向哈希算法,无法通过明文反查哈希值,因此你不能直接用明文token查询数据库,需要调整存储和查询逻辑:
第一步:调整token存储逻辑
写入token到数据库时,额外存储token的前6位明文作为查询前缀:
import bcrypt # 生成用户原始token raw_token = "生成的随机用户token" # 计算bcrypt哈希 hashed_token = bcrypt.hashpw(raw_token.encode('utf-8'), bcrypt.gensalt()).decode('utf-8') # 取前6位作为查询前缀 token_prefix = raw_token[:6] # 写入数据库 tokens_collection.insert_one({ "token_prefix": token_prefix, "hashed_token": hashed_token, "user_id": "关联的用户ID" # 可按需添加其他用户字段 })
第二步:修正登录验证逻辑
先通过token前缀查询到候选记录,再逐一做bcrypt比对:
@app.route('/account_login', methods=['POST']) def account_login(): try: if request.method == 'POST': tokens_collection = mongo.db.user_tokens raw_input_token = request.form.get('token', '').strip() if not raw_input_token: flash('Token不能为空') return redirect(url_for("account")) # 用前缀查询候选记录 input_prefix = raw_input_token[:6] matched_token_docs = tokens_collection.find({"token_prefix": input_prefix}) login_success = False current_user_id = None for doc in matched_token_docs: stored_hash = doc['hashed_token'].encode('utf-8') input_bytes = raw_input_token.encode('utf-8') if bcrypt.hashpw(input_bytes, stored_hash) == stored_hash: login_success = True current_user_id = doc['user_id'] break if login_success: # 不要存储明文token到session,存用户ID即可 session['user_id'] = current_user_id return redirect(url_for("account")) flash('Token输入错误,请重新输入') return redirect(url_for("account")) return redirect(url_for("account")) except Exception as e: print(f"account login error: {e}") flash('系统异常,请稍后重试') return redirect(url_for("account"))
内容的提问来源于stack exchange,提问作者ultralazer
相关产品推荐
相关产品推荐

