修改电子邮件地址:用户可以修改注册电子邮件的地址,不过接受新地址之前,必须使用确认邮件进行验证。为了验证新地址,应用发送一封包含令牌的邮件。服务器收到令牌后,再更新用户对象。服务器收到令牌之前,可以把新电子邮件地址保存在数据库一个新字段中,或者将其与id一起保存在令牌中。
1)点击修改电子邮件,进入“Change Your Email Address”界面:
2)提交1)中的表单发送一封电子邮件,并重定向到主界面:
templates/auth/change_email.html:修改电子邮件模板
{% extends 'base.html' %}
{% import "bootstrap/wtf.html" as wtf %}
{% block title %}Flasky - Change Email Address{% endblock %}
{% block page_content %}
<div class="page-header"><h1>Change Your Email Address</h1></div>
<div class="col-md-4">{{ wtf.quick_form(form) }}</div>
{% endblock %}
templates/auth/email/change_email.html:包含邮件修改令牌的邮件
<p>Dear {{ user.username }},</p>
<p>To confirm your new email address <a href="{{ url_for('auth.change_email', token=token, _external=True) }}">
click here</a>.</p>
<p>Alternatively, you can paste the following link in your browser's address bar:</p>
<p>{{ url_for('auth.change_email', token=token, _external=True) }}</p>
<p>Sincerely,</p>
<p>The Flasky Team</p>
<p><small>Note: replies to this email address are not monitored.</small></p>
auth/forms.py:修改邮箱表单
class ChangeEmailForm(FlaskForm):
email = StringField('New Email', validators=[DataRequired(), Length(1, 64), Email()])
password = PasswordField('Password', validators=[DataRequired()])
submit = SubmitField('Update Email Address')
def validate_email(self, field):
if User.query.filter_by(email=field.data).first():
raise ValidationError('Email already registered.')
3)处理1)中表单的视图函数
auth/views.py:处理ChangeEmailForm表单的视图函数
@auth.route('/change_email', methods=['GET', 'POST'])
@login_required
def change_email_request():
form = ChangeEmailForm()
if form.validate_on_submit():
if current_user.verify_password(form.password.data):
new_email = form.email.data
token = current_user.generate_email_change_token(new_email)
send_email(new_email, 'Confirm your email address', 'auth/email/change_email', user=current_user,
token=token)
flash('An email with instructions to confirm your new email '
'address has been sent to you.')
return redirect(url_for('main.index'))
else:
flash('Invalid email or password.')
return render_template('auth/change_email.html', form=form)
app/models.py:User模型中添加修改邮箱需要的令牌以及修改邮箱的方法:
def generate_email_change_token(self, new_email, expiration=3600):
s = Serializer(current_app.config['SECRET_KEY'], expiration)
return s.dumps({'change_email': self.id, 'new_email': new_email}).decode('utf-8')
def change_email(self, token):
s = Serializer(current_app.config['SECRET_KEY'])
try:
data = s.loads(token.encode('utf-8'))
except:
return False
if data.get('change_email') != self.id:
return False
new_email = data.get('new_email')
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
注:在产生加密令牌时,将用户输入的新邮件地址也保存在了令牌中,在修改电子邮件地址时,再从令牌中获取。
4)点击收到的包含邮箱修改令牌的电子邮件链接
5)处理4)中链接的视图处理函数
auth/views.py:
@auth.route('/change_email/<token>', methods=['GET', 'POST'])
@login_required
def change_email(token):
if current_user.change_email(token):
db.session.commit()
flash('Your email address has been updated.')
else:
flash('Invalid request.')
return redirect(url_for('main.index'))
注:由于User模型中已经封装了change_email方法,所以此处直接传入令牌,调用即可。
在4)中的主页中输入新的电子邮件地址登录,登录成功后将重定向到首页