Python项目实战 4.1:账号登录

目录

 一、用户名登录

二、多账号登录 

三、首页用户名展示

四、退出登录

五、判断用户是否登录


 一、用户名登录

1. 用户名登录逻辑分析

Python项目实战 4.1:账号登录_第1张图片

2. 用户名登录接口设计

1. 请求方式

选项 方案
请求方法 POST
请求地址 /login/

2. 请求参数:表单

参数名 类型 是否必传 说明
username string 用户名
password string 密码
remembered string 是否记住用户

3. 响应结果:HTML

字段 说明
登录失败 响应错误提示
登录成功 重定向到首页

3. 用户名登录后端逻辑(apps.users.views.py)


class LoginView(View):
    """用户登录"""

    def get(self, request):
        """提供用户登录页面"""
        return render(request, 'login.html')

    def post(self, request):
        """实现用户登录逻辑"""
        # 接收参数
        username = request.POST.get('username')
        password = request.POST.get('password')
        remembered = request.POST.get('remembered')

        # 校验参数
        if not all([username, password]):
            return http.HttpResponseForbidden('缺少必传参数')
        if not re.match(r'^[a-zA-Z0-9_-]{5,20}$', username):
            return http.HttpResponseForbidden('请输入正确的用户名或手机号')

        if not re.match(r'^[0-9A-Za-z]{8,20}$', password):
            return http.HttpResponseForbidden('密码最少8位,最长20位')

        # 认证用户:使用账号查询用户是否存在,如果用户存在,再校验密码是否正确
        user = authenticate(username=username, password=password)
        if user is None:
            return render(request, 'login.html', {'account_errmsg': '账号或密码错误'})

        # 状态保持
        login(request, user)
        # 使用remembered确定状态保持周期(实现记住登录)
        if remembered != 'on':
            # 没有记住登录:状态保持在浏览器会话结束后就销毁
            request.session.set_expiry(0) # 单位是秒
        else:
            # 记住登录:状态保持周期为两周:默认是两周
            request.session.set_expiry(None)

        # 响应结果
        # 先取出next
        next = request.GET.get('next')
        if next:
            # 重定向到next
            response = redirect(next)
        else:
            # 重定向到首页
            response = redirect(reverse('contents:index'))

        # 为了实现在首页的右上角展示用户名信息,我们需要将用户名缓存到cookie中
        # response.set_cookie('key', 'val', 'expiry')
        response.set_cookie('username', user.username, max_age=3600 * 24 * 15)

        # 用户登录成功,合并cookie购物车到redis购物车
        response = merge_carts_cookies_redis(request=request, user=user, response=response)

        # 响应结果
        return response

二、多账号登录 

  • Django自带的用户认证后端默认是使用用户名实现用户认证的。

  • 用户认证后端位置:django.contrib.auth.backends.ModelBackend。

  • 如果想实现 用户名和手机号都可以认证用户,就需要自定义用户认证后端。

  • 自定义用户认证后端步骤

    • 在users应用中新建utils.py文件
    • 新建类,继承自ModelBackend
    • 重写认证authenticate()方法
    • 分别使用用户名和手机号查询用户
    • 返回查询到的用户实例

 users.utils.py

from django.contrib.auth.backends import ModelBackend
import re
from .models import User


def get_user_by_account(account):
    """
    根据account查询用户
    :param account: 用户名或者手机号
    :return: user
    """
    try:
        if re.match('^1[3-9]\d{9}$', account):
            # 手机号登录
            user = User.objects.get(mobile=account)
        else:
            # 用户名登录
            user = User.objects.get(username=account)
    except User.DoesNotExist:
        return None
    else:
        return user


class UsernameMobileAuthBackend(ModelBackend):
    """自定义用户认证后端"""

    def authenticate(self, request, username=None, password=None, **kwargs):
        """
        重写认证方法,实现多账号登录
        :param request: 请求对象
        :param username: 用户名
        :param password: 密码
        :param kwargs: 其他参数
        :return: user
        """
        # 根据传入的username获取user对象。username可以是手机号也可以是账号
        user = get_user_by_account(username)
        # 校验user是否存在并校验密码是否正确
        if user and user.check_password(password):
            return user

Django自带认证后端源码:

Python项目实战 4.1:账号登录_第2张图片

在配置文件中配置自定义用户认证后端:

# 指定自定义的用户认证后端
AUTHENTICATION_BACKENDS = ['users.utils.UsernameMobileAuthBackend']

Python项目实战 4.1:账号登录_第3张图片

三、首页用户名展示

1. 首页用户名展示方案

方案一

  • 模板中 request 变量直接渲染用户名
  • 缺点:不方便做首页静态化
{% if user.is_authenticated %}
    
    {% else %}
    
{% endif %}

方案二

  • 发送ajax请求获取用户信息
  • 缺点:需要发送网络请求

方案三

  • Vue读取cookie渲染用户信息


结论:

  • 对比此三个方案,我们在本项目中选择 方案三

实现步骤:

  • 注册或登录后,用户名写入到cookie
  • Vue渲染主页用户名

2. 用户名写入到cookie:

登录方法 class LoginView(View) 中添加:

# 响应登录结果
response = redirect(reverse('contents:index'))

# 登录时用户名写入到cookie,有效期15天
response.set_cookie('username', user.username, max_age=3600 * 24 * 15)

return response

3. Vue渲染首页用户名

1.index.html



2.index.js

mounted(){
    // 获取cookie中的用户名
    this.username = getCookie('username');
},

四、退出登录

 1. logout()方法介绍

  1. 退出登录:

    • 回顾登录:将通过认证的用户的唯一标识信息,写入到当前session会话中
    • 退出登录:正好和登录相反(清理session会话信息)
  2. logout()方法:

    • Django用户认证系统提供了logout()方法
    • 封装了清理session的操作,帮助我们快速实现登出一个用户
  3. logout()位置:

    • django.contrib.auth.__init__.py文件中
logout(request)

2. logout()方法使用

class LogoutView(View):
    """退出登录"""

    def get(self, request):
        """实现退出登录逻辑"""
        # 清理session
        logout(request)
        # 退出登录,重定向到登录页
        response = redirect(reverse('contents:index'))
        # 退出登录时清除cookie中的username
        response.delete_cookie('username')

        return response

五、判断用户是否登录

1. is_authenticate 判断用户是否登录

介绍:

  • Django用户认证系统提供了方法request.user.is_authenticated()来判断用户是否登录。
  • 如果通过登录验证则返回True。反之,返回False
  • 缺点:登录验证逻辑很多地方都需要,所以该代码需要重复编码好多次。
class UserInfoView(View):
    """用户中心"""

    def get(self, request):
        """提供个人信息界面"""
        if request.user.is_authenticated():
            return render(request, 'user_center_info.html')
        else:
            return redirect(reverse('users:login'))

2. login_required装饰器 判断用户是否登录

定义扩展类方便项目中导入和使用(utils.views.py)

from django.contrib.auth.mixins import LoginRequiredMixin
from django import http

from wangye_mall.utils.response_code import RETCODE


class LoginRequiredJSONMixin(LoginRequiredMixin):
    """自定义判断用户是否登录的扩展类:返回JSON"""

    # 为什么只需要重写handle_no_permission?
    # 因为判断用户是否登录的操作,父类已经完成,子类只需要关心,如果用户未登录,对应怎样的操作
    def handle_no_permission(self):
        """直接响应JSON数据"""
        return http.JsonResponse({'code': RETCODE.SESSIONERR, 'errmsg': '用户未登录'})

users.views.py

class UserInfoView(LoginRequiredMixin, View):
    """用户中心"""

    def get(self, request):
        """提供用户中心页面"""
        # 如果LoginRequiredMixin判断出用户已登录,那么request.user就是登陆用户对象
        context = {
            'username': request.user.username,
            'mobile': request.user.mobile,
            'email': request.user.email,
            'email_active': request.user.email_active
        }
        return render(request, 'user_center_info.html', context)

 ps:子应用urls.py记得添加

    # 用户登录
    url(r'^login/$', views.LoginView.as_view(), name='login'),
    # 用户退出登录
    url(r'^logout/$', views.LogoutView.as_view(), name='logout'),
    # 用户中心
    url(r'^info/$', views.UserInfoView.as_view(), name='info'),

你可能感兴趣的:(Python-Django,python,http,安全)