I am writing a simple login which has one time passwords using the PyOTP library and SQLalchemy and a class I am using which works fine.
I want to save the current TOTP into the database once validated using this:
session = Session()
self.lastOtp = currentTotp
session.commit()
session.close()
But it doesn't update the database at all. I think it's because the method doesn't know it's the specific user object I am trying to update but I've tried adding self to various lines to figure it out but cannot. I've the following working:
methodSession = Session()
currentUser = methodSession.query(User).filter_by(emailAddress=self.emailAddress).one()
currentUser.lastOtp = currentTotp
methodSession.commit()
methodSession.close()
self.lastOtp = currentTotp
But that means another database query and I already have a User object which I can access as self.
This is the full user class
# user class
class User(Base):
__tablename__ = 'users'
id = Column(Integer, primary_key=True)
firstName = Column(String(64))
lastName = Column(String(64))
emailAddress = Column(String(128), index=True, unique=True)
passwordHash = Column(String(128))
secretKey = Column(BLOB)
lastOtp = Column(String(128))
def __repr__(self):
return '<User {}>'.format(self.emailAddress)
def set_password(self, password):
# function to set password hash
self.passwordHash = generate_password_hash(password)
def check_password(self, password):
# function to check password returning true or false
return check_password_hash(self.passwordHash, password)
def set_secret_key(self):
# function to set the secure secret key
pass
def get_secret_key(self):
# function to return the secure secret key
pass
def check_secret_key(self, secret_key):
# function to check the otp returning true or false
totp = pyotp.TOTP(self.get_secret_key())
currentTotp = totp.now()
if self.lastOtp == currentTotp:
return False
if totp.verify(secret_key):
session = Session()
self.lastOtp = currentTotp
session.commit()
session.close()
return True
return False
Expected behaviour:
session = Session()
myUser = session.query(User).filter_by(emailAddress='john@smith.com').one()
print("Last OTP: ", myUser.lastOtp)
>>> 987568
myUser.check_secret_key('123456')
>>> True
print("Last OTP: ", myUser.lastOtp)
>>> 123456
myUser.check_secret_key('123456')
>>> False
You need to add the object you want to save to the SQLAlchemy session. I do not see in your code where you are doing that. Specifically, here:
if totp.verify(secret_key):
session = Session()
self.lastOtp = currentTotp
session.commit()
session.close()
return True
you are creating the Session, then commit and close it, without adding an instance of the object you want to save to it. You are missing a session.add(...) call.
If the User
instance is already associated with a session, that session may be retrieved using Session.object_session :
def check_secret_key(self, secret_key):
# function to check the otp returning true or false
totp = pyotp.TOTP(self.get_secret_key())
currentTotp = totp.now()
if self.lastOtp == currentTotp:
return False
if totp.verify(secret_key):
session = Session.object_session(self)
self.lastOtp = currentTotp
session.commit()
return True
return False
Note that committing this session will commit any other changes already associated with it.
Looks like Matei's comment means this is the only solution:
def check_secret_key(self, secret_key):
# function to check the otp returning true or false
totp = pyotp.TOTP(self.get_secret_key())
currentTotp = totp.now()
if self.lastOtp == currentTotp:
return False
if totp.verify(secret_key):
methodSession = Session()
currentUser = methodSession.query(User).filter_by(emailAddress=self.emailAddress).one()
currentUser.lastOtp = currentTotp
methodSession.commit()
methodSession.close()
self.lastOtp = currentTotp
return True
return False
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.