账号激活策略

激活的方式有几种:

  • 邮箱
  • 短信
  • 人工审核

邮件激活

设计流程

  1. 用户注册提交信息
  2. 向注册时提交的邮箱中发送邮件
  3. 用户点击邮件的激活链接完成账号激活

所以这里要有两个功能:

  • 发送邮件需要:

    • 服务器

      • 邮箱服务器
      • 端口(不加密默认25,加密465)
    • 收件人的地址
    • 发件人的信息

      • 用户名
      • 密码
      • 内容
  • 点击邮件中的就激活链接

邮件发送

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>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;欢迎注册佩奇VIP,但您的账号还没有激活认证,请点击下面的激活按钮,进行激活。</p>
<a href="{{ activate_url }}">激活</a>
<p>如上面的激活按钮不可用,请将下面的地址复制到浏览器中进行激活。</p>
<p>{{ activate_url }}</p>
<h6>&nbsp;&nbsp;&nbsp;&nbsp;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

自增主键和uuid主键优劣分析

https://blog.csdn.net/XDSXHDYY/article/details/78994045?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.control&dist_request_id=1328627.308.16152998466103799&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.control

最后修改:2024 年 03 月 13 日
如果觉得我的文章对你有用,请随意赞赏