Flask账户注册(4)

Flask账户注册(4)

Flask账户注册

综合使用所学习过的知识,搭建登录页面

代码示例:https://github.com/ningwenyan/demo_code/tree/master/flask_demo_code/T26

总览

❯ tree
.
├── app.py
├── auth
│   ├── auth_form.py
│   ├── __init__.py
│   └── views.py
├── common
│   ├── errors.py
│   ├── exts.py
│   ├── __init__.py
│   ├── mailModel.py
│   └── sqlModel.py
├── config.py
├── manager.py
├── migrations
│   ├── alembic.ini
│   ├── env.py
│   ├── README
│   ├── script.py.mako
│   └── versions
│       ├── 44bc21866b0d_.py
│       └── __pycache__
│           └── 44bc21866b0d_.cpython-37.pyc
├── static
└── templates
    ├── 401.html
    ├── 403.html
    ├── 404.html
    ├── 500.html
    └── auth
        ├── change_email.html
        ├── change_password.html
        ├── index.html
        ├── login.html
        ├── mail
        │   ├── change_email.html
        │   ├── change_email.txt
        │   ├── confirm.html
        │   ├── confirm.txt
        │   ├── password_reset.html
        │   └── password_reset.txt
        ├── main
        │   └── reset_password.html
        ├── personal.html
        ├── register.html
        └── reset_password.html

设计修改密码

修改密码很容易,只要在登录的状态下,设计一个表单来修改即可.

<!----auth/change_password.html---->
   <h3>Change Password</h3>
   <form action="" method="post">
       {# 解决csrf_token #}
        <input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
       <div>
           <label for="">Old Password:</label>
           <input type="password" placeholder="old password" name="old_password">
       </div>
       <div>
           <label for="">New Password:</label>
           <input type="password" placeholder="new password" name="new_password">
       </div>
       <div>
           <label for="">Repeat Password:</label>
           <input type="password" placeholder="repeat Password" name="rep_password">
       </div>
       <div><input type="submit" value="change"></div>
   </form>

设计表单

# auth_form.py
# 修改密码表单
class ChangePasswordForm(FlaskForm):
   old_password = PasswordField(validators=[Length(124)])
   new_password = PasswordField(validators=[Length(124)])
   rep_password = PasswordField(validators=[EqualTo('new_password')])

修改视图

# 修改密码
@auth_bp.route('/change_password', methods = ['GET', 'POST'])
@login_required
def change_password():
   form = ChangePasswordForm()
   if form.validate_on_submit():
       old_password = form.old_password.data
       new_password = form.new_password.data
       if current_user.check_password(old_password):
           # 解密验证旧密码
           current_user.password = new_password
           db.session.add(current_user)
           db.session.commit()
           flash("您的密码已修改.")
           return redirect(url_for('auth.login'))
       else:
           flash("请输入正确的原密码.")
   return render_template('auth/change_password.html')

personal.html中添加修改密码

   <p><a href="{{ url_for('auth.change_password') }}">修改密码</a> </p>

登录验证:通过personal.html验证修改密码.需要注意的是current_user代理可以直接访问到用户.

增加忘记密码功能

新增加一个路由用于忘记密码时重置密码.它会给的注册邮箱发送一个带token连接用于修改密码

login.html新增加一个忘记密码的超链接

<!---login.html-->
<p><a href="{{ url_for('auth.reset_password_request') }}">Forget Password</a> </p>

设计路由

# 设置忘记密码
@auth_bp.route('/reset_password/', methods= ['GET', 'POST'])
def reset_password_request():
   form = ResetPasswordRequestForm()
   if form.validate_on_submit():
       email = form.email.data.lower()
       user = User.query.filter(User.email == email).first()
       if user is not None:
           # 如果数据库中存在user,就发送重置密码的邮件
           # 在数据库中重新创建一个 generate_reset_password_token 用于生成密码token
           token = user.generate_reset_password_token()
           # 发送邮件
           sendMail(user.email, '重置密码''password_reset', user=user, token=token)
       flash("请检查您的邮箱重置密码.")
       return redirect(url_for('auth.login'))
   return render_template('auth/reset_password.html')

reset_password.html中只包含一个内容,就是填写邮箱

<!-----reset_password---->
   <h3>Reset Password</h3>
   <form action="" method="post">
       {# 解决csrf_token #}
       <input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
       <div>
           <label for="">Email:</label>
           <input type="text" placeholder="email" name="email">
       </div>
       <input type="submit" name="Send Email">
   </form>

我们将通过其中的email来验证数据库中是否存在,并创建一个唯一的token,这里会新增加一个方法

# sqlModel.py

   #  生成 reset password token
   def generate_reset_password_token(self, expiration=3600):
       s = Serializer(current_app._get_current_object().config['SECRET_KEY'], expires_in=expiration)
       return s.dumps({'reset':self.id}).decode('utf-8')

这样,我们就会发送一个邮件给注册邮箱,它的内容也比较简单,它会带token跳转到填写密码的页面

# views.py
# 忘记密码,带token
@auth_bp.route('/reset_password/<token>', methods=['GET', 'POST'])
def reset_password(token):
   form = ResetPasswordForm()
   if form.validate_on_submit():
       new_password = form.password.data
       # 使用类方法验证token
       if User.check_reset_password(token, new_password):
           db.session.commit()
           flash("您的密码已更新!")
           return redirect(url_for('auth.login'))
       else:
           flash("您的账户不存在,请注册!")
           return redirect(url_for('auth.register'))
   return render_template('auth/main/reset_password.html')

这里的check_reset_password是新定义的方法

# sqlModel.py
   # 序列化消息并验证,这里使用静态方法,对比以上的类的方法
   @staticmethod
   def check_reset_password(token, new_password):
       s = Serializer(current_app._get_current_object().config['SECRET_KEY'])
       try:
           data = s.loads(token.encode('utf-8'))
       except:
           return False
       user = User.query.get(data.get('reset'))
       # 不是系统数据库中的用户,返回False
       if user is None:
           return False
       user.password = new_password
       db.session.add(user)
       return True

它使用的是静态方法,可以很方便的在User上操作,并设置一个新的密码.

设计修改邮箱

同样的方法,我们可以设计修改邮箱,它的好处是你必须是登录状态才能去修改邮箱.

先在personal.html添加一个跳转链接

   {#  修改邮箱  #}
   <p><a href="{{ url_for('auth.change_email_request') }}">修改邮箱</a> </p>

然后添加视图

# 修改邮箱
@auth_bp.route('/change_email/', methods = ['GET', 'POST'])
@login_required
def change_email_request():
   form = ChangeEmailForm()
   if form.validate_on_submit():
       # 表单验证成功,并在数据库中不存在邮箱
       password = form.password.data
       new_email = form.new_email.data.lower()
       if current_user.check_password(password):
           token = current_user.generate_change_email_token(new_email)
           sendMail(new_email, '更换新邮箱''change_email', user= current_user, token=token)
           flash('您的邮箱已更换,请在新邮箱中激活账户.')
           return redirect(url_for('auth.login'))
       else:
           flash('无效的邮箱或密码')
   return render_template('auth/change_email.html')

如上,我们需要设计一个新的token,专门为修改邮箱服务.它要包换原来的用户id,以及新邮箱来确保它的唯一性.

   # 验证邮箱token的token
   def generate_change_email_token(self,new_email,  expiration=3600):
       s = Serializer(current_app._get_current_object().config['SECRET_KEY'], expires_in=expiration)
       return s.dumps({'email':self.id, 'new_email': new_email}).decode('utf-8')

   def check_change_email_token(self, token):
       s = Serializer(current_app._get_current_object().config['SECRET_KEY'])
       try:
           data = s.loads(token.encode('utf-8'))
       except:
           return False
       new_email = data.get('new_email')
       if data.get('email') != self.id:
           return False
       if new_email is None:
           return False
       # 判断重复
       if self.query.filter_by(email = new_email).first() is not None:
           return False
       # 修改
       self.email = new_email
       db.session.add(self)
       return True

注意,我们的发送邮件的模板在auth/mail/

   <p>您好,{{ user.username }}</p>
   <p>点击<a href="{{ url_for('auth.change_email', token=token, _external=True) }}">修改</a>按钮修改你的账户.</p>
   <p>您也可以双击以下连接激修改账户:</p>
   <p>{{ url_for('auth.change_email', token=token, _external=True) }}</p>
   <p>如果已修改,请忽略此邮件.</p>

然后根据模板设计视图

@auth_bp.route('/change_email/<token>')
@login_required
def change_email(token):
   if current_user.check_change_email_token(token):
       db.session.commit()
       flash('您的邮箱已修改.')
   else:
       flash("链接已过期,请重新修改邮箱.")
   return redirect(url_for('auth.login'))

使用Flask Bootstrap美化网页

– END –


原文始发于微信公众号(Flask学习笔记):Flask账户注册(4)

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/36400.html

(0)
小半的头像小半

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!