账号激活策略
激活的方式有几种:
- 邮箱
- 短信
- 人工审核
邮件激活
设计流程
- 用户注册提交信息
- 向注册时提交的邮箱中发送邮件
- 用户点击邮件的激活链接完成账号激活
所以这里要有两个功能:
发送邮件需要:
服务器
- 邮箱服务器
- 端口(不加密默认25,加密465)
- 收件人的地址
发件人的信息
- 用户名
- 密码
- 内容
点击邮件中的就激活链接
链接中存在用户的唯一标识
- http://xxxxx/activate/?u_token=YYYY
- u_token 放入缓存中作为key, 而value可以是user_id
u_token使用uuid
- uuid:https://baike.baidu.com/item/UUID/5921266?fr=aladdin
- UUID是指在一台机器上生成的数字,它保证对在同一时空中的所有机器都是唯一的。通常平台会提供生成的API。按照开放软件基金会(OSF)制定的标准计算,用到了以太网卡地址、纳秒级时间、芯片ID码和随机数。
- 标识具有时效性
- 标指具有使用次数限制
邮件发送
Django中封装了邮件模块使其变为函数可以直接调用:
from django.core.mail import send_mail
send_mail(
'Subject here',
'Here is the message.',
'from@example.com',
['to@example.com'],
fail_silently=False,
)
我们登录发送邮箱的账户配置允许第三方使用邮箱(设置为开启),并且获得授权码:
添加url:
url(r'sendmail/', views.send_email)
我们应该将重复使用的参数如邮箱主机名,发送邮箱端口,邮箱账号,授权码号放入settings.py中,方便之后重复调用。
settings.py:
EMAIL_HOST = 'smtp.qq.com'
EMAIL_PORT = 25
EMAIL_HOST_USER = '1526340366@qq.com'
EMAIL_HOST_PASSWORD = 'jevyehupxgajjggc' # 授权码
views:
接着我们将发送邮件的函数完善好
def send_email(request):
subject = 'peiqi1 Activate' # 邮件主题
message = 'Hello' # 邮件信息
from_email = '152xxxxxxx6@qq.com' # 发送方
recipient_list = ['xxxxxxx@qq.com'] # 接收方
send_mail(subject=subject, message=message, from_email=from_email, recipient_list=recipient_list)
return HttpResponse('send_success')
测试:
邮箱中也可以看到
我们还可以使用html_message参数来发送经过html渲染过的内容:
views:
def send_email(request):
subject = 'peiqi1 Activate' # 邮件主题
message = '<h1>Hello</h1>' # 邮件信息
from_email = '1526340366@qq.com' # 发送方
recipient_list = ['746199864@qq.com'] # 接收方
send_mail(subject=subject, message='', html_message=message, from_email=from_email, recipient_list=recipient_list)
return HttpResponse('send_success')
这里的mseeage参数填空只是是为了占住参数位置,否则会报错提示缺少参数,实际上邮箱显示的是html_message字段中的内容。
测试:
可以看到显示html样式。
激活链接
制作激活链接网页,先创建网页模板:
<h4>Dear{{ username }}:</h4>
<p> 欢迎注册佩奇VIP,但您的账号还没有激活认证,请点击下面的激活按钮,进行激活。</p>
<a href="{{ activate_url }}">激活</a>
<p>如上面的激活按钮不可用,请将下面的地址复制到浏览器中进行激活。</p>
<p>{{ activate_url }}</p>
<h6> Best Wishes</h6>
<h6>From WuWei</h6>
views中对模板进行填坑:
def send_email(request):
subject = 'peiqi1 Activate' # 邮件主题
from_email = '1526340366@qq.com' # 发送方
recipient_list = ['746199864@qq.com'] # 接收方
data = {
'username': 'Tom',
'activate_url': 'http://www.justinwuwei.cn/',
} # 为激活邮件的模板中传入对应用户的信息
html_message = loader.get_template('user/activate.html').render(data)
send_mail(subject=subject, message='', html_message=html_message, from_email=from_email, recipient_list=recipient_list)
return HttpResponse('send_success')
测试:
现在我们要设计激活链接,样式为:
http://xxxxx/activate/?u_token=YYYY
我们要有一个activate的url,每次当我们去发邮件的时候都要生成一个token去验证。
url(r'^activate/', views.activate, name='activate'),
u_token 放入缓存中作为key, 而value可以是user_id
将之前测试使用的url :sendmail删除。
在settings.py中加入:
SERVER_HOST = '127.0.0.1'
SERVER_PORT = '8000'
将views中的sendmail函数移动至views_helper中,并且修改为:
def send_email_activate(username, receive, u_token): # 接收的参数为用户的邮箱
subject = f'{username} peiqi1 Activate' # 邮件主题
from_email = EMAIL_HOST_USER # 发送方
recipient_list = [receive, ] # 接收方
data = {
'username': username,
'activate_url': f'http://{SERVER_HOST}:{SERVER_PORT}/peiqi1/activate/?u_token={u_token}',
} # 为激活邮件的模板中传入对应用户的信息
html_message = loader.get_template('user/activate.html').render(data)
send_mail(subject=subject, message='', html_message=html_message, from_email=from_email, recipient_list=recipient_list)
views: 26 - 28行,生成uuid作为u_token传入发送邮箱函数中
def register(request):
if request.method == 'GET':
data = {
'title': '注册'
}
return render(request, 'user/register.html', context=data)
elif request.method == 'POST':
username = request.POST.get('username')
email = request.POST.get('email')
password = request.POST.get('password')
icon = request.FILES.get('icon')
# password = hash_str(password) # 进行哈希加密
password = make_password(password)
user = peiqi1user()
user.u_usename = username
user.u_password = password
user.u_email = email
user.u_icon = icon
user.save()
u_token = uuid.uuid4().hex # 使用uuid生成u_token,hex是转换成字符串型
print(u_token)
send_email_activate(username, email, u_token) # 邮箱验证刚刚注册的用户
# 注册成功之后重定向到登录界面
return redirect(reverse('peiqi1:login'))
测试:
当我们注册提交之后收到邮件
到这里我们就实现了生成u_token,接下来我们要将u_token保存到redis的缓存中
views:第27行存入缓存,所用到的模块名为:
from django.core.cache import cache
def register(request):
if request.method == 'GET':
data = {
'title': '注册'
}
return render(request, 'user/register.html', context=data)
elif request.method == 'POST':
username = request.POST.get('username')
email = request.POST.get('email')
password = request.POST.get('password')
icon = request.FILES.get('icon')
# password = hash_str(password) # 进行哈希加密
password = make_password(password)
user = peiqi1user()
user.u_usename = username
user.u_password = password
user.u_email = email
user.u_icon = icon
user.save()
u_token = uuid.uuid4().hex # 使用uuid生成u_token,hex是转换成字符串型
cache.set(u_token, user.id, timeout=60*5) # 生成u_token之后,加入缓存中,有效时间为5分钟
print(u_token)
send_email_activate(username, email, u_token) # 邮箱验证刚刚注册的用户
# 注册成功之后重定向到登录界面
return redirect(reverse('peiqi1:login'))
接着配置缓存:
https://github.com/JASTINWUWEI/PythonCourse/blob/master/web/django/djangocache.md(文档)
添加配置到settings.py中:
CACHES = {
"default": {
"BACKEND": "django_redis.cache.RedisCache",
"LOCATION": "redis://127.0.0.1:6379/1",
"OPTIONS": {
"CLIENT_CLASS": "django_redis.client.DefaultClient",
}
}
}
不要忘记启动redis:
C:\redis>redis-server.exe redis.windows.conf
接着验证u_token,激活账号,验证u_token的函数如下:
views:
def activate(request):
u_token = request.GET.get('u_token')
user_id = cache.get(u_token)
if user_id: # 如果user_id存在,就进行激活的策略处理
cache.delete(u_token) # 获取到user_id之后u_token就从缓存删除
user = peiqi1user.objects.get(pk=user_id) # 找到对应的用户
user.is_active = True # 修改成激活状态
user.save()
return redirect(reverse('peiqi1:login')) # 重定向到登录界面
return render(request, 'user/activate_fail.html')
新建activate_fail.html:
{% extends 'base_user.html' %} {# 继承自base_user #}
{% block content %}
<div>
<h3>激活失败,请重新申请激活</h3>
</div>
{% endblock %}
测试:
成功收到邮件
点击链接,观察数据库后台,可以发现is_activate字段属性变为1.
错误信息
- 先将错误信息存储下来
在错误显示页面获取错误信息
- 保证错误信息只显示一次(获取到数据之后直接将自己删除)
- 密码重置时的验证也是这样,token使用完就删除。
登录时判断是否激活
登录账号时,除了检查密码之外,还需要检查是否激活,(大部分是先检查密码是否正确,然后检查是否激活)
views:
def login(request):
if request.method == 'GET':
error_message = request.session.get('error_message') # 开头获取error_message
data = {
'title': '登录',
}
if error_message: # 如果存在error_message,就显示到浏览器上
del request.session['error_message']
data['error_message'] = error_message # 这样error_message就传到了页面中
return render(request, 'user/login.html', context=data)
elif request.method == 'POST':
username = request.POST.get('username')
password = request.POST.get('password')
print(password)
users = peiqi1user.objects.filter(u_usename=username)
if users.exists(): # 如果用户名存在
user = users.first()
if check_password(password, user.u_password): # 哈希验证密码
if user.is_active: # 验证是否激活
# 使用cookie或者session将用户登录状态存下
request.session['user_id'] = user.id
return redirect(reverse('peiqi1:mine'))
else:
print('用户未激活')
request.session['error_message'] = 'not activae' # 使用session传递错误原因至浏览器,这样重定向之后浏览器就能显示到登录错误原因
return redirect(reverse('peiqi1:login'))
else:
print('密码错误')
request.session['error_message'] = '密码错误'
return redirect(reverse('peiqi1:login'))
request.session['error_message'] = '用户不存在'
print('用户不存在')
return redirect(reverse('peiqi1:login'))
4,10-12行:如果有error_message就传入页面,没有就不传
27,31,35: 使用session传递错误原因至浏览器,这样重定向之后浏览器就能显示到登录错误原因。
login.html中:
<div class="'container">
<form method="post" action="{% url 'peiqi1:login' %}" onsubmit="return parse_data()"> {# 指定post请求类型 #}
{% csrf_token %} {# Django自带放跨站攻击 #}
<p>{{ error_message }}</p>
<div class="form-group">
<label for="username_input">用户名</label>
<input name="username" type="text" class="form-control" id="username_input" placeholder="用户名/邮箱">
</div>
第五行传入错误信息至前端
测试:这样我们登录时,出现密码错误,用户不存在,账号未激活的错误都能反馈给用户,并且刷新一次网页错误原因就消失。
后期优化
我们在后台发送邮件时,用户的界面可以先跳转到登录界面,而不是需要等待邮件发送完成再去跳转,所以需要实现异步发送邮件的功能。
商城系统应如何设计ID(如用户、商品、订单等)生成规则?
http://www.imall.com.cn/news-4856-72209.html
此处评论已关闭