我认为如果你能展示你正在使用的一些代码(相关的模型、路由和模板)可能会有所帮助,这样我们就可以更好地帮助你。话虽如此,我认为您正在寻找的关键元素是session
Flask 的对象。有了这个,您可以在路由之间保留信息,在本例中为username
.
就像您提到的那样,不是在一个模板和路由中验证密码和 2fa 令牌,而是将它们一分为二:
- 验证密码的一种途径和模板
- 用于验证 2fa 令牌的一种路线和模板
例如,查看下面的两条路线和关联注释:
路线.py
from flask import session
@app('/login', methods=['GET', 'POST'])
def login():
form = LoginForm(request.form)
status = 200
if request.method == 'POST' and form.validate():
user = User.query.filter_by(username=form.username.data).first()
# set the username in the current session
session['username'] = user.username
# check the 2FA is implemented
if user.otp_secret is None:
return redirect(url_for('app.two_factor_setup'))
if user and user.validate(form.password.data): # first only validate the password
#login_user(user) --> move this to the other route ('two_factor_input' in this example)
return redirect(url_for('app.two_factor_input'))
else:
flash('Wrong credentials')
status = 401
return render_template('login.html', form=form), status
@app.route('/two_factor_input', methods=['GET', 'POST'])
def two_factor_input():
form = Token2FAForm(request.form)
status = 200
if 'username' not in session:
return redirect(url_for('app.login'))
user = User.query.filter_by(username=session['username']).first()
if user is None:
flash('Something went wrong')
return redirect(url_for('app.login'))
if request.method == 'POST':
if user and user.verify_totp(form.token.data):
login_user(user)
flash('Succesvol logged in')
return redirect(url_for('app.index'))
else:
flash('Something went wrong')
return redirect(url_for('app.two_factor_input'))
return render_template('two_factor_input.html', form=form)
作为“附件”,我附上了一个“用户”模型的示例,如果这可能对您有所帮助。
PS:我使用pyotp
了 2fa链接的模块
模型.py
class User(UserMixin, db.Model):
__tablename__ = 'users'
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(64), unique=True, index=True)
password_hash = db.Column(db.String(256))
otp_secret = db.Column(db.String(16))
def __init__(self, username, password, otp_secret, **kwargs):
super(User, self).__init__(**kwargs)
self.username = username
self.password = password
self.otp_secret = otp_secret
if self.otp_secret is None:
# generate a random secret
self.otp_secret = base64.b32encode(os.urandom(10)).decode('utf-8')
def validate(self, password):
return check_password_hash(self.password_hash, password)
@property
def password(self):
raise AttributeError('password is not a readable attribute')
@password.setter
def password(self, password):
self.password_hash = generate_password_hash(password)
# methods for 2factor-authentication
def get_totp_uri(self):
return 'otpauth://totp/Your App%20Token:{0}?secret={1}&issuer=yourapp'.format(self.username, self.otp_secret)
def verify_totp(self, token):
totp = pyotp.TOTP(self.otp_secret)
return totp.verify(token)