在学习Flask-Web开发这本书的第八章遇到了问题,就是在数据库模型中添加确认用户账户的功能时,有这样一段代码:
class User(UserMixin,db.Model):
__tablename__ = 'users'
id = db.Column(db.Integer,primary_key=True)
email = db.Column(db.String(64),unique=True,index=True)
username=db.Column(db.String(64),unique=True,index=True)
role_id = db.Column(db.Integer,db.ForeignKey('roles.id'))
password_hash = db.Column(db.String(128))
confirmed = db.Column(db.Boolean,default=False)
@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)
def verify_password(self,password):
return check_password_hash(self.password_hash,password)
def generate_confirmation_token(self,expiration=3600):
s=Serializer(current_app.config['SECRET_KEY'],expiration)
return s.dumps({'confirm':self.id})
def confirm(self,token):
s=Serializer(current_app.config['SECRET_KEY'])
try:
data=s.loads(token)
except:
return False
if data.get("confirm") != self.id:
return False
self.confirmed = True
db.session.add(self)
db.session.commit()
return True
def __repr__(self):
return '<User %r>' % self.username
confirm()方法验证令牌。
其中,有一段是这样的:if data.get("confirm") != self.id,正常情况下data返回的不就是原数据么({'confirm':self.id}),加这段代码的意义是什么?
书中有解释:confirm()方法还检查令牌中的id是否和存储在current_user中的已登录用户匹配。这里的current_user是否就是指正在进行验证的这个用户?对于Flask来说,尚未确认的用户也算已登录的用户吗,即current_user.is_authentiacated为True。将代码改为
if data.get("confirm") != current_user.get_id():
可否?
以及最后一句话,添加这段代码:if data.get("confirm") != self.id,即使恶意用户知道如何生成签名令牌,也无法确认别人的账户。账户应该是指注册或者登录时的email吧,这段代码确认了confirm数据是否为用户唯一id号,和用户账户(email)有什么关系?
需要注意的是这里的
token
和SECRET_KEY
。这里的data经过了一次
data=s.loads(token)
,如果token和SECRET_KEY不正确的话,get
得到的id也是不正确的,这样就起到了验证的作用。这里的账户指的是每个账户自己的id,就算恶意用户成功伪造了token,因为用户的id号不正确,这里无法成功验证。
登录和确认是两个属性,这两个之间没有耦合的关系,没有登录的账户也可以是确认过的,所以没有确认的账户也可以是登录状态的。