Flask用户登陆系统(五)-----发送邮件

这次的发送邮件是利用了Flask自带的邮件功能,而且利用了token的加密认证方式,会更加的安全(参考常见的认证方式

关于Json  Web  Token(jwt)

可以参考阮一峰的博客,注意JWT的特点

总结一下就是JWT可以帮你把JSON信息用某种算法加密成一个令牌(token)然后每次登陆的时候用户就可以拿着这个令牌来登陆

 

使用JWT

1.1准备与测试

pip install PyJWT

>>> import jwt

>>> encoded_jwt = jwt.encode({'some': 'payload'}, 'secret', algorithm='HS256')
>>> encoded_jwt
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzb21lIjoicGF5bG9hZCJ9.4twFt5NiznN84AWoo1d7KO1T_yoc0Z6XOpOVswacPZg'

>>> jwt.decode(encoded_jwt, 'secret', algorithms=['HS256'])
{'some': 'payload'}

 

send_email.py

创建多线程发送更改密码的邮件

from email import encoders
from email.header import Header
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.utils import formataddr, parseaddr
from flask import render_template
from threading import Thread
import smtplib

from_addr = "***********"
password = "*************"
smtplib_server = 'smtp.sina.com'


def send_regest_email(nickname,user_password,email):
    msg = MIMEMultipart()
    msg['From'] = Header(from_addr)
    msg['Subject'] = Header('Bear Home Regist Information')
    content = MIMEText(
            "Your Bear Home username is %s,password is %s" % (
                nickname.data, user_password.data),
            'plain',
            'utf-8'
    )
    msg.attach(content)
    try:
        server = smtplib.SMTP()
        server.connect(smtplib_server, 25)
        server.set_debuglevel(1)
        server.login(from_addr, password)
        server.sendmail(from_addr, email.data, msg.as_string())
        print("Successfully send")
    except smtplib.SMTPException as e:
        server.quit()
        print('发送失败')
        pass


def send_reset_email(html_body,to_email):
    content = html_body
    msg = MIMEMultipart()
    msg['From'] = Header(from_addr)
    msg['Subject'] = Header('Bear Home Reset Password Information')
    msg.attach(MIMEText(content,'html','utf-8'))
    try:
        server = smtplib.SMTP()
        server.connect(smtplib_server, 25)
        server.set_debuglevel(1)
        server.login(from_addr, password)
        server.sendmail(from_addr, to_email, msg.as_string())
        print("Successfully send")
    except smtplib.SMTPException as e:
        server.quit()
        print('发送失败')
        pass

def send_password_reset_email(user,to_email):
    token=user.get_reset_password_token()
    html_body=render_template('emails/reset_password.html',user=user,token=token)
    thread_01=Thread(target=send_reset_email,args=(html_body,to_email.data))
    # send_reset_email( html_body=render_template('emails/reset_password.html',user=user,token=token),
    #             to_email=to_email.data
    # )
    thread_01.start()
    

这里的user.get_reset_password_token()就是获取更改密码的令牌,也就是加密后:

 #以字符串形式生成一个JWT令牌
    def get_reset_password_token(self,expires_in=600):
        return jwt.encode(
            {'reset_password':self.id,'exp':time()+expires_in},
            app.config['SECRET_KEY'],algorithm='HS256').decode('utf-8')

exp字段是JWTs的标准,如果它存在,则表示令牌的到期时间。 如果一个令牌有一个有效的签名,但是它已经过期,那么它也将被认为是无效的。 对于密码重置功能,我会给这些令牌10分钟的有效期。

app.config['SECRET_KEY']是秘密密钥用于创建加密签名

get_reset_password_token()函数以字符串形式生成一个JWT令牌。 请注意,decode('utf-8')是必须的,因为jwt.encode()函数将令牌作为字节序列返回,但是在应用中将令牌表示为字符串更方便。

@app.route('/reset_password_request',methods=['GET', 'POST'])#, methods=['GET', 'POST']
def reset_password_request():
    print("hahahha")
    if current_user.is_authenticated:
        return redirect(url_for('index'))
    form = ResetPasswordRequestForm()
    if form.validate_on_submit():
        user = User.query.filter_by(email=form.email.data).first()
        print(user)
        if user:
            send_password_reset_email(user,form.email)
        flash('Check your email for the instructions to reset your password')
        return redirect(url_for('login'))
    return render_template('reset_password_request.html',
                           title='Reset Password', form=form)

@app.route('/reset_password/<token>', methods=['GET', 'POST'])
def reset_password(token):
    if current_user.is_authenticated:
        return redirect(url_for('index'))
    user=User.verify_reset_password_token(token)
    print("------------------------------------------------------------------")
    print(token)
    print(user)
    if not user:
        return redirect(url_for('index'))
    form=ResetPasswordForm()
    if form.validate_on_submit():
        user.set_password(form.password.data)
        db.session.commit()
        flash('Your password has been reset.')
        return redirect(url_for('login'))
    return render_template('reset_password.html',form=form)

关于这个代码块最重要的是verify_reset_password_token函数:

 @staticmethod
    def verify_reset_password_token(token):
        try:
            id=jwt.decode(token,app.config['SECRET_KEY'],algorithms=['HS256'])['reset_password']#获取解码后的reset_password
        except:
            return
        return User.query.get(id)#获取

解码token,获取id,返回对应的用户

 

流程:

填写邮箱

 

收到邮件

 

点击链接后就可以更改密码了

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值