Reset Password
add a method to the user model "similar to the way to confirm an account"
flasky/app/models.py
From werkzeug.security import Generate_password_hash, check_password_hash from itsdangerous Import Timedjsonwebsignatureserializer as serializer from flask import Current_app from Flask_login import usermixin from. Import db, Login_manager Class Role (db). Model): __tablename__ = ' roles ' id = db. Column (db. Integer, primary_key=true) name = db. Column (db.
String (+), unique=true) users = db.relationship (' User ', backref= ' role ', lazy= ' dynamic ') def __repr__ (self): Return ' <role%r> '% Self.name class User (usermixin, DB. Model): __tablename__ = ' users ' id = db. Column (db. Integer, primary_key=true) email = db. Column (db. String (+), unique=true, index=true) Username = db. Column (db. String (+), Unique=true, index=true) role_id = db. Column (db. Integer, Db. ForeignKey (' roles.id ')) Password_hash = db. Column (db. String (+)) 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.passwo Rd_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 = Seriali Zer (current_app.config[' Secret_key ')) Try:data = s.loads (token) Except:return Fa LSE if Data.get (' confirm ')! = Self.id:return False self.confirmed = True Db.session.a DD (self) return True ########################################################### def generate_reset_token (self , expiration=3600): #增加generate_reset_token方法, the cryptographic signature used to generate the user's id s = Serializer (current_app.config[' Secret_key '), Expiration) #先产生An instance of the serializer class with the key set and expiration time return S.dumps ({' Reset ': Self.id}) #返回一个加密签名 def reset_password (self, t Oken, New_password): #增加更改密码的方法, accept token encrypted signature, new password S = serializer (current_app.config[' Secret_key ']) #产生实例 s try:data = s.loads (token) Except:return False #试着解析加密签名, get the dictionary data, otherwise return F
Alse if Data.get (' reset ')! = Self.id:return false #如果data字典中的reset的值不等于用户的id, returns false Self.password = New_password #否则, update user password db.session.add (self) #提交到数据库 return True # Returns True Def __repr__ (self): return ' <user%r> '% self.username ######################################### ################ @login_manager. User_loader def load_user (user_id): Return User.query.get (int (user_id))
Table
From FLASK_WTF import Form from wtforms import Stringfield, Passwordfield, Booleanfield, Submitfield from Wtforms.validato RS Import Required, Length, Email, Regexp, Equalto from wtforms import ValidationError from:
Models import User Class LoginForm (Form): email = stringfield (' email ', validators=[required (), Length (1, 64), Email ()]) password = Passwordfield (' Password ', validators=[required ()]) REM Ember_me = Booleanfield (' Keep me Logged in '), submit = Submitfield (' Log in ') class Registrationform (Form): Email = Stringfield (' email ', validators=[required (), Length (1, +), Email ()]) use Rname = Stringfield (' Username ', validators=[Required (), Length (1, +), Regexp (' ^[a-za-z][a-za-z0-9_.]
*$ ', 0, ' Usernames must has only letters, ' ' numbers, dots or underscores ')] Password = passwordField (' Password ', validators=[Required (), Equalto (' Password2 ', message= ' passwords must match. ')]) Password2 = Passwordfield (' Confirm password ', validators=[required ()]) Submit = Submitfield (' Register ') def valid Ate_email (Self, field): If User.query.filter_by (Email=field.data). First (): Raise ValidationError (' Emai
L already registered. ') def validate_username (Self, field): If User.query.filter_by (Username=field.data). First (): Raise Valida
Tionerror (' Username already in use. ') Class Changepasswordform (Form): Old_password = Passwordfield (' Old password ', validators=[required ()]) password = P Asswordfield (' New password ', validators=[Required (), Equalto (' Password2 ', message= ' passwords must match ')]) p Assword2 = Passwordfield (' Confirm new password ', validators=[required ()]) Submit = Submitfield (' Update password ') # # # ######################################################## Class Passwordresetrequestform (Form): #定义填写辅助找回密码的电子邮件地址的表格 email = stringfield (' email ', validators=[required (), Length (1, 64),
Email ()]) Submit = Submitfield (' Reset Password ') class Passwordresetform (Form): #定义填写新密码的表格 email = stringfield (' email ', validators=[required (), Length (1, +), email ()]) password = Passwordfield (' New password ', validators=[Required (), Equalto (' Password2 ', message= ' passwords Must match ')] Password2 = Passwordfield (' Confirm password ', validators=[required ()]) Submit = Submitfield (' Reset Password ') ########################################################### def validate_email (Self, field): If Us
Er.query.filter_by (Email=field.data). First () is None:raise validationerror (' Unknown email address. ')
Control Center Controller
flasky/app/auth/views.py
From flask import Render_template, redirect, request, Url_for, flash from flask_login import Login_user, Logout_user, Logi N_required, \ Current_User from. Import Auth from: Import db from: Models import User from: Email import send_email from. Forms Import LoginForm, Registrationform, changepasswordform,\ Passwordresetrequestform, Passwordresetform #导入重置密码的电子邮箱表格, fill in the form of the new password @auth. Before_app_request def before_request (): If Current_user.is_authenti cated \ and not current_user.confirmed \ and Request.endpoint[:5]! = ' auth. ' \ and req Uest.endpoint! = ' static ': Return redirect (Url_for (' auth.unconfirmed ')) @auth. Route ('/unconfirmed ') def Unconfir Med (): If current_user.is_anonymous or Current_user.confirmed:return redirect (Url_for (' Main.index ')) Retu RN render_template (' auth/unconfirmed.html ') @auth. Route ('/login ', methods=[' GET ', ' POST ') def login (): Form = Login
Form () if Form.validate_on_submit (): user = User.query.filter_by (email=form.email.data). First () If User is not None and User.verify_password (FORM.P Assword.data): Login_user (user, Form.remember_me.data) return redirect (Request.args.get (' Next ') or
Url_for (' Main.index ')) Flash (' Invalid username or password. ') Return render_template (' auth/login.html ', Form=form) @auth. Route ('/logout ') @login_required def logout (): Logout_use
R () Flash (' You had been logged out. ') Return Redirect (Url_for (' Main.index ')) @auth. Route ('/register ', methods=[' GET ', ' POST ') def register (): Form = Regi Strationform () if Form.validate_on_submit (): User = User (Email=form.email.data, username=f Orm.username.data, Password=form.password.data) db.session.add (user) Db.session.commit
() token = User.generate_confirmation_token () send_email (User.email, ' Confirm Your account ', ' Auth/email/confirM ', User=user, Token=token) Flash (' A confirmation email with been sent to you by email. ') Return Redirect (Url_for (' Auth.login ')) return render_template (' auth/register.html ', Form=form) @auth. Route ('/confir M/<token> ') @login_required def confirm (token): If Current_user.confirmed:return redirect (Url_for (' main . Index ')) if Current_user.confirm (token): Flash (' You had confirmed your account.
Thanks! ')
Else:flash (' The confirmation link is invalid or have expired. ') Return Redirect (Url_for (' Main.index ')) @auth. Route ('/confirm ') @login_required def resend_confirmation (): token = CU Rrent_user.generate_confirmation_token () send_email (Current_user.email, ' Confirm Your account ', ' auth/e
Mail/confirm ', User=current_user, Token=token) Flash (' A new confirmation email has been sent to your by email. ') Return Redirect (Url_for (' Main.index ')) @auth. Route ('/change-password ', methods=[' GET ', ' POST ') @login_required def change_password (): Form = Changepasswordform () if Form.validate_on_submit (): If Current_User . Verify_password (form.old_password.data): Current_user.password = Form.password.data db.session.ad
D (current_user) Flash (' Your password has been updated. ')
Return Redirect (Url_for (' Main.index ')) else:flash (' Invalid password. ') Return Render_template ("auth/change_password.html", Form=form) ################################################## ####### #点击登录时的忘记密码, enter/rest view function @auth. Route ('/reset ', methods=[' GET ', ' POST ') def password_reset_request (): If not CU Rrent_user.is_anonymous: #如果现在的用户已经登录, is already a normal user return redirect (url_for (' Main.index ')) #直接重定向到主页 for m = Passwordresetrequestform () #建立表格实例 if Form.validate_on_submit (): #如果表格不为空, otherwise the empty table page directly appears user = user. Query.filter_by (Email=form.email.data). First () #从数据库中筛选出email为表格填写的email的用户 if user: #如果有 token = User.generate_reset_token () #产生加密签名 send_email (User.email, ' Res
Et Your Password ', ' Auth/email/reset_password ', User=user, Token=token, Next=request.args.get (' Next ')) #发送带有token链接的电子邮件, if successful, redirect to the previously visited Web page Flas
H (' an mail with instructions to reset your password have been sent to you. ') #显示flash消息 return Redirect (Url_for (' Auth.login ')) #重定向的蓝本中的登录函数 is to display the login page return render_template (' A Uth/reset_password.html ', Form=form) @auth. Route ('/reset/<token> ', methods=[' GET ', ' POST ') #点击邮件中的链接,
Process def password_reset (token) via this route: if not Current_user.is_anonymous:return redirect (Url_for (' Main.index ')) #如果已经是登录用户, redirect directly to home page form = Passwordresetform () #建立填写密码的表格实例 if Form.validate_on_submit (): #如果表格中的数据不为空, Otherwise, the empty table directly displays user = User.query.filter_by (email=form.email.data). FirsT () #从数据库中筛选出email为表格填写的email的用户 if user is None:return redirect (Url_for (' Main.index ')) #如果没有这个用户, redirect to Home if User.reset_password (token, form.password.data): Flash (' Your password have be
En updated. ') Return Redirect (Url_for (' Auth.login ')) #如果能执行重置密码的函数, the flash message is displayed, redirected to the login page Else:return Redi Rect (url_for (' Main.index ')) #否则重定向到主页 return render_template (' auth/reset_password.html ', form=form) ###### #####################################################
email templates for sending mail (TXT and HTML format)
Flasky/app/templates/auth/email/reset_password.txt
Dear {{User.username}}, to
reset your password click on the following link:
{{url_for (' Auth.password_reset '), to Ken=token, _external=true)}} If you had not
requested a password reset simply ignore the this message.
Sincerely, the
Flasky Team
note:replies to this email address is not monitored.
flasky/app/templates/auth/email/reset_password.html
<p>dear {{user.username}},</p>
<p>to Reset your password <a href= ' {{url_for (' Auth.password_ Reset ', Token=token, _external=true)}} ">click here</