I've been following along to Corey Schafer's awesome youtube tutorial on the basic flaskblog. In addition to Corey's code, I`d like to add a logic, where users have to verify their email-address before being able to login. I've figured to do this with the URLSafeTimedSerializer from itsdangerous, like suggested by prettyprinted here.
The whole token creation and verification process seems to work. Unfortunately due to my very fresh python knowledge in general, I can't figure out a clean way on my own how to get that saved into the sqlite3 db. In my models I've created a Boolean Column email_confirmed with default=False which I am intending to change to True after the verification process. My question is: how do I best identify the user (for whom to alter the email_confirmed Column) when he clicks on his custom url? Would it be a good practice to also save the token inside a db Column and then filter by that token to identify the user?
Here is some of the relevant code:
User Class in my modely.py
class User(db.Model, UserMixin):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(20), unique=True, nullable=False)
email = db.Column(db.String(120), unique=True, nullable=False)
image_file = db.Column(db.String(20), nullable=False, default='default_profile.jpg')
password = db.Column(db.String(60), nullable=False)
date_registered = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)
email_confirmed = db.Column(db.Boolean(), nullable=False, default=False)
email_confirm_date = db.Column(db.DateTime)
projects = db.relationship('Project', backref='author', lazy=True)
def get_mail_confirm_token(self, expires_sec=1800):
s = URLSafeTimedSerializer(current_app.config['SECRET_KEY'], expires_sec)
return s.dumps(self.email, salt='email-confirm')
@staticmethod
def verify_mail_confirm_token(token):
s = URLSafeTimedSerializer(current_app.config['SECRET_KEY'])
try:
return s.loads(token, salt='email-confirm', max_age=60)
except SignatureExpired:
return "PROBLEM"
Registration Logic in my routes (using a users blueprint):
@users.route('/register', methods=['GET', 'POST'])
def register():
if current_user.is_authenticated:
return redirect(url_for('dash.dashboard'))
form = RegistrationForm()
if form.validate_on_submit():
hashed_password = bcrypt.generate_password_hash(form.password.data).decode('utf-8')
user = User(username=form.username.data, email=form.email.data, password=hashed_password)
db.session.add(user)
db.session.commit()
send_mail_confirmation(user)
return redirect(url_for('users.welcome'))
return render_template('register.html', form=form)
@users.route('/welcome')
def welcome():
return render_template('welcome.html')
@users.route('/confirm_email/<token>')
def confirm_email(token):
user = User.verify_mail_confirm_token(token)
current_user.email_confirmed = True
current_user.email_confirm_date = datetime.utcnow
return user
The last parts current_user.email_confirmed = True
and current_user.email_confirm_date =datetime.utcnow
are probably the lines in question. Like stated above the desired entries aren't made because the user is not logged in at this stage, yet.
Im grateful for any help on this!
Thanks a lot in advance!