我正在尝试通过向 Gmail 帐户发送电子邮件来添加重置用户密码的功能。我一直在关注CoreySchafer YouTube 教程和Miguel Grinberg 教程来实现这一点。
总体思路是用户将收到密码重置请求表的提示,他们将在其中输入他们想要重置密码的电子邮件地址。单击“请求重置密码”后,将显示一条消息,表明电子邮件已发送到他们的 Gmail 帐户。通过单击电子邮件中的链接,用户将能够重置其密码。
相关文件名的代码如下:
文件:路由.py
# Reset Password Request Route
@app.route("/reset_password", methods = ["GET", "POST"])
def reset_password_request():
if current_user.is_authenticated:
return redirect(url_for("dashboard"))
form = ResetPasswordRequestForm()
if form.validate_on_submit():
user = User.query.filter_by(email = form.email.data).first()
if user:
send_password_reset_email(user)
flash("Please check your email for the instructions to reset your password")
return redirect(url_for("login"))
return render_template("reset_password_request.html", title = "Request For Reset Password", form = form)
# Password Reset Route
@app.route("/reset_password/<token>", methods = ["GET", "POST"])
def reset_password(token):
if current_user.is_authenticated:
return redirect(url_for("dashboard"))
user = User.verify_reset_password_token(token)
if not user:
flash("Invalid Token")
return redirect(url_for("reset_password_request"))
form = ResetPasswordForm()
if form.validate_on_submit():
user.set_password(form.password.data)
db.session.commit()
flash("Congratulations! Your password has been reset successfully.")
return redirect(url_for("login"))
return render_template("reset_password.html", title = "Reset Password", form = form)
文件:forms.py
# Reset Password Request Form
class ResetPasswordRequestForm(FlaskForm):
email = StringField("Email", validators = [DataRequired(message = "Email Address is required."), Email()], render_kw = {"placeholder": "Email Address"})
submit = SubmitField("Request Password Reset")
def validate_email(self, email):
user = User.query.filter_by(email = email.data).first()
if user is None:
raise ValidationError("There is no account with that email. You must register first.")
# Password Reset Form
class ResetPasswordForm(FlaskForm):
password = PasswordField("Password", validators = [DataRequired(message = "Password is required.")], render_kw = {"placeholder": "Password"})
confirm_password = PasswordField("Repeat Password", validators = [DataRequired(message = "Password Confirmation is required."), EqualTo("password")], render_kw = {"placeholder": "Confirm Password"})
submit = SubmitField("Reset Password")
文件:email.py
from flask import render_template
from flask_mail import Message
from app import app, mail
from threading import Thread
# Sending Emails Asynchronously
def send_async_email(app, msg):
with app.app_context():
mail.send(msg)
# Email Sending Wrapper Function
def send_email(subject, sender, recipients, text_body, html_body):
msg = Message(subject, sender = sender, recipients = recipients)
msg.body = text_body
msg.html = html_body
Thread(target = send_async_email, args = (app, msg)).start()
# Send Password Reset Email Function
def send_password_reset_email(user):
token = user.get_reset_password_token()
send_email("【Task Manager】Reset Your Password",
sender = app.config["ADMINS"][0],
recipients = [user.email],
text_body = render_template("email/reset_password.txt", user = user, token = token),
html_body = render_template("email/reset_password.html", user = user, token = token))
文件:models.py
from itsdangerous import TimedJSONWebSignatureSerializer as Serializer
# Reset Password Support in User Model
def get_reset_password_token(self, expires_sec = 1800):
s = Serializer(app.config["SECRET_KEY"], expires_sec)
return s.dumps({"user_id": self.id}).decode("utf-8")
# Verifying Reset Password Token in User Model
@staticmethod
def verify_reset_password_token(token):
s = Serializer(app.config["SECRET_KEY"])
try:
user_id = s.loads(token)["user_id"]
except:
return None
return User.query.get(user_id)
文件:reset_password_request.html
{% extends "layout.html" %}
{% block content %}
<h1>Task Manager</h1>
<form action="" method="POST">
{{ form.hidden_tag() }}
<div>
{{ form.email(size=64) }}
</div>
{% for error in form.email.errors %}
<span style="color: red;">{{ error }}</span>
{% endfor %}
<div>
{{ form.submit() }}
</div>
</form>
{% endblock %}
文件:reset_password.html
{% extends "layout.html" %}
{% block content %}
<h1>Task Manager</h1>
<form action="" method="POST" novalidate>
{{ form.hidden_tag() }}
<div>
{{ form.password(size=32) }}
</div>
{% for error in form.password.errors %}
<span style="color: red;">{{ error }}</span>
{% endfor %}
<div>
{{ form.confirm_password(size=32) }}
</div>
{% for error in form.confirm_password.errors %}
<span style="color: red;">{{ error }}</span>
{% endfor %}
<div>
{{ form.submit() }}
</div>
</form>
{% endblock %}
我已将环境变量保存在根目录的 .env 文件中。
SECRET_KEY="simple-is-better-than-complex"
MAIL_SERVER="smtp.googlemail.com"
MAIL_PORT=587
MAIL_USE_TLS=True
MAIL_USERNAME="jeet.java.13"
MAIL_PASSWORD="pass123"
还在项目根目录中创建了 config.py 文件。
from dotenv import load_dotenv
load_dotenv(override=True)
import os
basedir = os.path.abspath(os.path.dirname(__file__))
# Application Configurations
class Config(object):
# Function: Getting Environment Variables
def get_env_var(name):
try:
return os.environ[name]
except KeyError:
message = "Expected Environment Variable '{}' Not Set!".format(name)
raise Exception(message)
# SECRET_KEY Configuration
SECRET_KEY = os.getenv("SECRET_KEY")
SQLALCHEMY_DATABASE_URI = "sqlite:///" + os.path.join(basedir, "tms.db")
SQLALCHEMY_TRACK_MODIFICATIONS = False
# EMAIL CONFIGURATION
MAIL_SERVER = os.getenv("MAIL_SERVER")
MAIL_PORT = int(os.getenv("MAIL_PORT")) or 25
MAIL_USE_TLS = os.getenv("MAIL_USE_TLS")
MAIL_USERNAME = os.getenv("MAIL_USERNAME")
MAIL_PASSWORD = os.getenv("MAIL_PASSWORD")
ADMINS = ["jeet.java.13@gmail.com"]
终端结果:
"POST /reset_password HTTP/1.1" 302 -
我还为我的 Gmail 帐户打开了“安全性较低的应用程序”,但仍然无法发送电子邮件。在执行 Flask 应用程序期间,终端中没有错误。
期待您最亲切的支持。