【Django开发】0到1美多商城项目md教程第6篇:账号登录,1. 用户名登录逻辑分析【附代码文档】

news2024/11/28 22:43:44

美多商城完整教程(附代码资料)主要内容讲述:欢迎来到美多商城!,项目准备。展示用户注册页面,创建用户模块子应用。用户注册业务实现,用户注册前端逻辑。图形验证码,图形验证码接口设计和定义。短信验证码,避免频繁发送短信验证码。账号登录,用户名登录。登录,登录开发文档。用户基本信息,查询并渲染用户基本信息。收货地址,省市区三级联动。收货地址,展示地址前后端逻辑。商品数据库表设计,SPU和SKU。准备商品数据,容器化方案Docker。首页广告,展示首页商品频道分类。商品列表页,列表页面包屑导航。商品搜索,Haystack扩展建立索引。商品详情页,统计分类商品访问量。购物车管理,添加购物车。购物车管理,删除购物车。订单,结算订单。提交订单,使用乐观锁并发下单。对接系统,订单支付功能。页面静态化,首页广告页面静态化。MySQL读写分离,MySQL主从同步。

全套笔记资料代码移步: 前往gitee仓库查看

感兴趣的小伙伴可以自取哦,欢迎大家点赞转发~


全套教程部分目录:


部分文件图片:

账号登录

用户名登录

1. 用户名登录逻辑分析

2. 用户名登录接口设计

1.请求方式

选项方案
请求方法POST
请求地址/login/
>
2.请求参数:表单
参数名类型是否必传说明
usernamestring用户名
passwordstring密码
rememberedstring是否记住用户
>
3.响应结果:HTML
字段说明
登录失败响应错误提示
登录成功重定向到首页

3. 用户名登录接口定义

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

    def get(self, request):
        """
        提供登录界面
        :param request: 请求对象
        :return: 登录界面
        """
        pass

    def post(self, request):
        """
        实现登录逻辑
        :param request: 请求对象
        :return: 登录结果
        """
        pass

4. 用户名登录后端逻辑

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

    def get(self, request):
        """
        提供登录界面
        :param request: 请求对象
        :return: 登录界面
        """
        return render(request, 'login.html')

    def post(self, request):
        """
        实现登录逻辑
        :param request: 请求对象
        :return: 登录结果
        """
        # 接受参数
        username = request.POST.get('username')
        password = request.POST.get('password')
        remembered = request.POST.get('remembered')

        # 校验参数
        # 判断参数是否齐全
        if not all([username, password]):
            return http.HttpResponseForbidden('缺少必传参数')

        # 判断用户名是否是5-20个字符
        if not re.match(r'^[a-zA-Z0-9_-]{5,20}$', username):
            return http.HttpResponseForbidden('请输入正确的用户名或手机号')

        # 判断密码是否是8-20个数字
        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)
        # 设置状态保持的周期
        if remembered != 'on':
            # 没有记住用户:浏览器会话结束就过期
            request.session.set_expiry(0)
        else:
            # 记住用户:None表示两周后过期
            request.session.set_expiry(None)

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

5. 知识要点

  1. 登录的核心思想:认证和状态保持

  2. 通过用户的认证,确定该登录用户是美多商场的注册用户。

  3. 通过状态保持缓存用户的唯一标识信息,用于后续是否登录的判断。

多账号登录

  • Django自带的用户认证后端默认是使用用户名实现用户认证的。
  • 用户认证后端位置:django.contrib.auth.backends.ModelBackend。

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

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

  • 在users应用中新建utils.py文件

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

1. 自定义用户认证后端

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

2. 配置自定义用户认证后端

1.Django自带认证后端源码

2.配置自定义用户认证后端

# 指定自定义的用户认证后端


AUTHENTICATION_BACKENDS = ['users.utils.UsernameMobileAuthBackend']

3. 测试自定义用户认证后端

4. 知识要点

  1. Django自带的用户认证系统只会使用用户名去认证一个用户。

  2. 所以我们为了实现多账号登录,就可以自定义认证后端,采用其他的唯一信息去认证一个用户。

首页用户名展示

1. 首页用户名展示方案

方案一

  • 模板中 request 变量直接渲染用户名
  • 缺点:不方便做首页静态化
{% if user.is_authenticated %}
    <div class="login_btn fl">
        欢迎您:<em>{{ user.username }}</em>
        <span>|</span>
        <a href="#">退出</a>
    </div>
    {% else %}
    <div class="login_btn fl">
        <a href="login.html">登录</a>
        <span>|</span>
        <a href="register.html">注册</a>
    </div>
{% endif %}

方案二

  • 发送ajax请求获取用户信息
  • 缺点:需要发送网络请求
<div class="login_btn fl">
    {# ajax渲染 #}
</div>

方案三

  • Vue读取cookie渲染用户信息
<div v-if="username" class="login_btn fl">
    欢迎您:<em>[[ username ]]</em>
    <span>|</span>
    <a href="#">退出</a>
</div>
<div v-else class="login_btn fl">
    <a href="login.html">登录</a>
    <span>|</span>
    <a href="register.html">注册</a>
</div>

结论:

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

实现步骤:

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


response = redirect(reverse('contents:index'))



# 注册时用户名写入到cookie,有效期15天


response.set_cookie('username', user.username, max_age=3600 * 24 * 15)

return response
# 响应登录结果


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

<div v-if="username" class="login_btn fl">
    欢迎您:<em>[[ username ]]</em>
    <span>|</span>
    <a href="#">退出</a>
</div>
<div v-else class="login_btn fl">
    <a href="login.html">登录</a>
    <span>|</span>
    <a href="register.html">注册</a>
</div>

2.index.js

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

退出登录

1. logout()方法介绍

  1. 退出登录:

  2. 回顾登录:将通过认证的用户的唯一标识信息,写入到当前session会话中

  3. 退出登录:正好和登录相反(清理session会话信息)

  4. logout()方法:

  5. Django用户认证系统提供了logout()方法

  6. 封装了清理session的操作,帮助我们快速实现登出一个用户

  7. logout()位置:

  8. 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

3. 知识要点

  1. 退出登录的核心思想就是清理登录时缓存的状态保持信息。
  2. 由于首页中用户名是从cookie中读取的。所以退出登录时,需要将cookie中用户名清除。

判断用户是否登录

1. 展示用户中心界面

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

    def get(self, request):
        """提供个人信息界面"""
        return render(request, 'user_center_info.html')

需求:

  • 当用户登录后,才能访问用户中心。
  • 如果用户未登录,就不允许访问用户中心,将用户引导到登录界面。

实现方案:

  • 需要判断用户是否登录。
  • 根据是否登录的结果,决定用户是否可以访问用户中心。

2. 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'))

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

  • Django用户认证系统提供了装饰器login_required来判断用户是否登录。

  • 内部封装了is_authenticate

  • 位置:django.contrib.auth.decorators

  • 如果通过登录验证则进入到视图内部,执行视图逻辑。

  • 如果未通过登录验证则被重定向到LOGIN_URL配置项指定的地址。

  • 如下配置:表示当用户未通过登录验证时,将用户重定向到登录页面。

LOGIN_URL = '/login/'

1.装饰as_view()方法返回值

提示:

  • login_required装饰器可以直接装饰函数视图,但是本项目使用的是类视图。
  • as_view()方法的返回值就是将类视图转成的函数视图。

结论:

  • 要想使用login_required装饰器装饰类视图,可以间接的装饰as_view()方法的返回值,以达到预期效果。
url(r'^info/$', login_required(views.UserInfoView.as_view()), name='info'),
class UserInfoView(View):
    """用户中心"""

    def get(self, request):
        """提供个人信息界面"""
        return render(request, 'user_center_info.html')

2.定义View子类封装login_required装饰器

  • 提示:LoginRequired(object)依赖于视图类View,复用性很差。
url(r'^info/$', views.UserInfoView.as_view(), name='info'),
class LoginRequired(View):
  """验证用户是否登陆"""

  @classmethod
  def as_view(cls, **initkwargs):
      # 自定义as_view()方法中,调用父类的as_view()方法
      view = super().as_view()
      return login_required(view)


class UserInfoView(LoginRequired):
    """用户中心"""

    def get(self, request):
        """提供个人信息界面"""
        return render(request, 'user_center_info.html')

3.定义obejct子类封装login_required装饰器

  • 提示:LoginRequired(object)不依赖于任何视图类,复用性更强。
url(r'^info/$', views.UserInfoView.as_view(), name='info'),
class LoginRequired(object):
  """验证用户是否登陆"""

  @classmethod
  def as_view(cls, **initkwargs):
      # 自定义as_view()方法中,调用父类的as_view()方法
      view = super().as_view()
      return login_required(view)


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

    def get(self, request):
        """提供个人信息界面"""
        return render(request, 'user_center_info.html')

4.定义验证用户是否登录扩展类

  • 提示:定义扩展类方便项目中导入和使用(meiduo_mall.utils.views.py)
class LoginRequiredMixin(object):
  """验证用户是否登录扩展类"""

  @classmethod
  def as_view(cls, **initkwargs):
      # 自定义的as_view()方法中,调用父类的as_view()方法
      view = super().as_view()
      return login_required(view)
class UserInfoView(LoginRequiredMixin, View):
    """用户中心"""

    def get(self, request):
        """提供个人信息界面"""
        return render(request, 'user_center_info.html')

4. 登录时next参数的使用

1.next参数的效果


2.next参数的作用

  • 由Django用户认证系统提供,搭配login_required装饰器使用。
  • 记录了用户未登录时访问的地址信息,可以帮助我们实现在用户登录成功后直接进入未登录时访问的地址。
# 响应登录结果


next = request.GET.get('next')
if next:
    response = redirect(next)
else:
    response = redirect(reverse('contents:index'))

5. 知识要点

  1. 判断用户是否登录依然使用状态保持信息实现。
  2. 项目中很多接口都是需要用户登录才能访问的,所以为了方便编码,我们将判断用户登录的操作封装到装饰器中。
  3. 登录时next参数的作用是为了方便用户从哪里进入到登录页面,登录成功后就回到哪里。

登录

未完待续, 同学们请等待下一期

全套笔记资料代码移步: 前往gitee仓库查看

感兴趣的小伙伴可以自取哦,欢迎大家点赞转发~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1577623.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Windows:IntelliJ IDEA Ultimate 安装 PHP 插件

在 IntelliJ IDEA Ultimate 中安装 PHP 插件&#xff0c;支持PHP开发调试 首先&#xff0c;进入File > Setting&#xff1a; 再次选择Plugins&#xff0c;然后选择上面的 Marketplace。 在搜索栏中输入 PHP&#xff0c;然后单击左侧的 Install 进行安装就可以了。 安装成功…

SD-WAN组成及关键技术解析

云桥通SD-WAN作为下一代网络连接技术&#xff0c;由控制平面、数据平面和管理平面三部分组成&#xff0c;共同构建了灵活、可管理和高效的网络架构。 1、控制平面&#xff1a; 控制平面负责决策制定和流量管理&#xff0c;在云桥通SD-WAN网络中扮演关键角色。基于软件定义网络…

转圈游戏——快速幂

目录 题目 思路 代码 题目 思路 每个小朋友移动一次的位置为&#xff0c;移动 q 次的位置则为。那么题目要求移动 &#xff0c;最后的位置为 。 但 的范围是&#xff0c;而总的移动次数是 。时间复杂度是在&#xff0c;因此是一定不能硬算的&#xff0c;肯定会超时。那么该…

【架构七】Hadoop

什么是Hadoop? Hadoop是一个存储系统计算框架的软件大数据处理框架。 Hadoop的核心&#xff0c;说白了就是HDFS和MapReduce&#xff0c;HDFS为海量数据提供了存储&#xff0c;而MapReduce为海量数据提供了计算框架。HBase是一个分布式的、面向列的开源数据库。属于Nosql。 …

微信小程序之事件

1、什么是事件 UI界面的程序需要和用户互动&#xff0c;例如用户可能会点击你界面上某个按钮&#xff0c;又或者长按某个区域&#xff0c;这类反馈应该通知给开发者的逻辑层&#xff0c;需要将对应的处理状态呈现给用户。 有些时候程序上的“行为反馈”不一定是用户主动触发的&…

详解简单的shell脚本 --- 命令行解释器【Linux后端开发】

首先附上完整代码 #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <sys/types.h> #include <sys/wait.h> //命令行解释器 //shell 运行原理&#xff1a;通过让子进程执行命令&#xff0c;父进…

计算机体系结构(1) 介绍和基础

为了跟上我们组学习的进度&#xff0c;打好体系结构的基础&#xff0c;接下来我会持续的学习计算机体系结构的知识。参考的课程是 苏黎世联邦理工 ETH Zurich&#xff1a;Digital Design and Computer Architect Lecture 1: Introduction and Basics_哔哩哔哩_bilibili 这一…

BioXCell,1H6--InVivoMAb anti-canine CD34

1H6单克隆抗体与犬CD34发生反应。CD34是一种I型单体唾液酸粘蛋白样糖蛋白&#xff0c;存在于许多干细胞群体中。CD34由骨髓和外周血中的造血祖细胞以及一些间充质干细胞、基质细胞、胚胎成纤维细胞、肿瘤细胞和成人血管内皮细胞表达。CD34经常被用作量化用于造血干细胞移植后该…

根证书和中间证书安装配置

下载根证书 根证书是建立信任链的基础。一旦客户端安装了根证书&#xff0c;它即可验证由该根证书签发的所有证书。这使得客户端可以信任与该根证书相关的所有服务器和应用程序&#xff0c;从而建立起一个完整的信任链。 如果您的业务用户通过浏览器访问您的Web业务&#xff…

【uniapp】个推H5号码认证一键登录(附代码)

前言 最近在做APP、h5产品&#xff0c;登陆注册成了难题。邮箱验证多数人不会使用&#xff0c;还是短信方便点&#xff0c;短信可以采用号码认证和验证码的方式&#xff0c;前者稍微便宜的&#xff0c;关于性价比和上手程度我推荐个推&#xff0c; 于是有了今天这篇案例记录&a…

低代码如何集成多平台(企业微信、钉钉、飞书)SDK,且听我细细道来

前言 我们是一家做低代码产品开发的公司&#xff0c;我司的低代码产品支持在多个平台环境内使用&#xff1a;有钉钉、企业微信、微信、飞书、Web浏览器&#xff08;如谷歌&#xff09;&#xff0c;后续还会接入更多平台。面对这么多平台&#xff0c;每个平台的SDK可能一致&…

磁盘类型与IOPS性能指标

目录 1.磁盘的访问模式 2.磁盘分类 2.1 HDD机械磁盘 2.1.1 机械磁盘性能 2.1.2 IOPS 2.1.3 提升IOPS性能手段 2.1.4 RAID技术 RAID 0 RAID 1 RAID 5 RAID 6 RAID 10 RAID 50 RAID总结 2.2 SSD固态硬盘 2.2.1 查看磁盘调度算法 2.2.2 修改磁盘调度算法 2.2.3 …

lottery-攻防世界

题目 flag在这里要用钱买&#xff0c;这是个赌博网站。注册个账号&#xff0c;然后输入七位数字&#xff0c;中奖会得到相应奖励。 githacker获取网站源码 &#xff0c;但是找到了flag文件但是没用。 bp 抓包发现api.php&#xff0c;并且出现我们的输入数字。 根据题目给的附…

DNFOMP:杂乱环境中自动驾驶汽车导航的动态神经场最优运动规划器

DNFOMP&#xff1a;杂乱环境中自动驾驶汽车导航的动态神经场最优运动规划器 附赠自动驾驶学习资料和量产经验&#xff1a;链接 摘要 本文介绍了DNFOMP&#xff1a;杂乱环境中自动驾驶汽车导航的动态神经场最优运动规划器。动态变化环境中的运动规划是自动驾驶中最复杂的挑战之…

RA8900CE计时芯片介绍及开发方案

计时芯片 就是一个需要连接32.768k晶振的RTC芯片 规格书阅读 首先我们先读懂这个芯片是怎么用的。 引脚表 封装是这样的&#xff0c;一共10个引脚。 基本上一看这个引脚表就知道大概。 T1和T2是工厂测试的&#xff0c;不用管。 SCL和SDA是IIC通讯用的。 FOUT和FOE就是链…

文献速递:深度学习胰腺癌诊断--胰腺肿瘤的全端到端深度学习诊断

Title 题目 Fully end-to-end deep-learning-based diagnosis of pancreatic tumors 胰腺肿瘤的全端到端深度学习诊断 01 文献速递介绍 胰腺癌是最常见的肿瘤之一&#xff0c;预后不良且通常是致命的。没有肿瘤的患者只需要进一步观察&#xff0c;而胰腺肿瘤的诊断需要紧…

C/C++中局部变量static用法实例

1. 普通局部变量存储于进程栈空间&#xff0c;使用完毕会立即释放&#xff0c;静态局部变量使用static修饰符定义&#xff0c;即使在声明时未赋初值&#xff0c;编译器也会把它初始化为0&#xff0c;并且静态局部变量存储于进程的全局数据区&#xff0c;即使函数返回&#xff0…

用three.js做一个3D汉诺塔游戏(下)

本文由孟智强同学原创。 接上期&#xff1a;《用three.js做一个3D汉诺塔游戏&#xff08;上&#xff09;》 在上一期&#xff0c;我们成功地搭建了基础的 3D 场景。在本期中&#xff0c;我们将对场景进行优化&#xff0c;使其在视觉上更加真实&#xff0c;并为场景中的物体添加…

golang es查询的一些操作,has_child,inner_hit,对索引内父子文档的更新

1.因为业务需要查询父文档以及其下子文档&#xff0c;搞了很久才理清楚。 首先还是Inner_hits,inner_hits只能用在nested,has_child,has_parents查询里面 {"query": {"nested": {"path": "comments","query": {"match…

vulhub之fastjson篇-1.2.27-rce

一、启动环境 虚拟机:kali靶机:192.168.125.130/172.19.0.1(docker地址:172.19.0.2) 虚拟机:kali攻击机:192.168.125.130/172.19.0.1 本地MAC:172.XX.XX.XX 启动 fastjson 反序列化导致任意命令执行漏洞 环境 1.进入 vulhub 的 Fastjson 1.2.47 路径 cd /../../vulhub/fa…