django 登录流程实现

news2025/1/8 18:02:24

一、简介:

1、用户输入正确的用户名、密码、验证码点击登录即可跳转到管理员页面。

2、用户输入错误的用户名或者密码或者验证码需要错误信息提示(数据校验)

 二、实现步骤

1、新建一个项目(创建项目过程和数据库略,可参考我的往期文章)

2、新建 templates 文件夹下新建登录页 login.html 和管理员页面 admin.html

3、model.py 新建一个管理员类,然后命令行运行 这两条命令,创建一张表

python manage.py makemigrations     python manage.py migrate
class Admin(models.Model):
    username = models.CharField(verbose_name="用户名",max_length=32)
    password = models.CharField(verbose_name="密码",max_length=64)
    def __str__(self):
        return self.username

表建立好之后,向数据库表中添加一条数据

 sql:

insert into appback_admin(username,password)values(root",123456);

 

 

4、views.py 

视图函数中所做的事情有点多

1、登录页面其实就是提交表单数据,这里使用了 django  的 modelform

class LoginForm(forms.Form):
    username = forms.CharField(
        label="用户名",
        widget=forms.TextInput,
        required=True
    )
    password = forms.CharField(
        label="密码",
        widget=forms.PasswordInput(render_value=True),
        required=True
    )
    code = forms.CharField(
        label="验证码",
        widget=forms.TextInput,
        required=True
    )

2、表单提交的密码需要加密存入数据库,使用了 md5 加密

 from appback.util.encrypt import md5
def clean_password(self):
        pwd = self.cleaned_data.get("password")
        return md5(pwd)

3、表单提交的用户名与密码需要与数据库中管理员表中的数据进行对比校验

admin_object = Admin.objects.filter(**form.cleaned_data).first()  # 数据库校验
        if not admin_object:
            form.add_error("password","用户名或密码错误")
            return render(request,'login.html',{"form":form})

4、此处登录使用了验证码验证,验证码利用 python 的第三方库 pillow 生成的一个简单的字母验证。

from appback.util.Verification_Code import Verification_Code
from io import BytesIO
def image_code(request):
    img,code_str = Verification_Code()
    print(code_str)
    request.session["image_code"] = code_str  # 讲图片验证码写入到 session 中
    request.session.set_expiry(60)  # 设置 60s 超时
    stream = BytesIO()
    img.save(stream,'png')  # 把图片内容写入到内存中
    return HttpResponse(stream.getvalue())

5、为了避免一张验证码被多次不停的使用,需要设置一个过期时间。

request.session.set_expiry(60)

6、用户提交了错误的用户名或者密码或者验证码,需要返回错误信息,此次利用了

form.add_error()

7、用户登录成功向用户的浏览器 session 中写入用户的 ID等其他信息,根据是否有 session 信息检查用户是否登录。

# 用户名密码正确,生成随机字符串写入到浏览器cookie 和session中
 request.session["info"] = {"id":admin_object.id,"username":admin_object.username}  # 例如当前用户名
request.session.set_expiry(60*60*24*7) # 七天免登录

查看用户的 sesion  

 8、创建一个新文件夹 middleware 下新建一个auth.py 新建一个类,这是一个中间件,获取用户当前的 url 判断有无 session 信息,有就继续,没有就返回到登录,同时需要将登录页面设置为不需要验证 session 信息就可以访问,这样才能重定向成功到登录页面,否则会出错。

class AuthMiddleware(MiddlewareMixin):
    def process_request(self,request):
        # 排除不需要登录就能访问的页面
        if request.path_info in ["/login","/image/code"]: # 获取当前用户请求的 url
            return
        # 读取当前访问用户的 session 信息
        info_dict = request.session.get("info")
        if info_dict:
            return
        # 没有登录回到登录页面
        return redirect('/login')
    def process_response(self,request,response):
        return response

三、效果如下所示

登陆:

 

 四、全部代码:

login.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>登录</title>
</head>
<body>
    <div>
        <div>
            <h3>用户登录</h3>
            <form class="form" method="post" novalidate>
                {% csrf_token %}
                <div class="username">
                    <label>用户名:</label>
                    {{ form.username }}
                    <span style="color:red;font-size:12px;">{{form.username.errors.0}}</span>
                </div>
                <div class="pwd">
                    <label>密码:</label>
                    {{ form.password }}
                    <span style="color:red;font-size:12px;">{{form.password.errors.0}}</span>
                </div>
                <div class="code">
                    <label>验证码:</label>
                    {{ form.code }}
                    <img src="/image/code" style="width:120px;height:40px;">
                    <span style="color:red;font-size:12px;">{{form.code.errors.0}}</span>
                </div>
                <div class="sub">
                    <input type="submit" value="登录">
                </div>
            </form>
        </div>
    </div>
</body>
<style>
    .form{
    width:280px;
    height:150px;
    border: 1px solid #666;
    padding:20px 10px;
    position: relative;
	box-shadow:2px 2px 3px gray,
	    -2px -2px 3px gray;
    }
    .pwd>input,.username>input{
    margin:10px 0px;
    width:200px;
    }
    .pwd>label,.username>label{
    display: inline-block;
    width:65px;
    }
    .sub>input{
    width:80px;
    position: absolute;
    bottom: 1%;
	left: 35%;
    }
    .code>input{
    width:60px;margin-right:15px;
    }
</style>
</html>

admin.html  (模板继承此处不做介绍)

<!--该html 继承模板 layout.html-->
{% extends 'layout.html' %}
{% block content %}
<div>
  <h2>管理员列表</h2>
  <a href="/adminadd">新增管理员</a>
  <table class="pure-table pure-table-bordered">
    <thead>
    <tr>
      <th>ID</th>
      <th>用户名</th>
      <th>密码</th>
      <th>操作</th>
    </tr>
  </thead>
    <tbody>
    {% for obj in queryset %}
      <tr>
        <td>{{obj.id}}</td>
        <td>{{obj.username}}</td>
        <td>********</td>
        <td>
          <a href="admin/{{ obj.id }}/edit">编辑</a>
          <a href="admin/{{ obj.id }}/delete">删除</a>
          <a href="admin/{{ obj.id }}/reset">重置密码</a>

        </td>
      </tr>
    {% endfor %}
    </tbody>
  </table>
</div>
{% endblock %}

models.py

# 创建管理员表
class Admin(models.Model):
    username = models.CharField(verbose_name="用户名",max_length=32)
    password = models.CharField(verbose_name="密码",max_length=64)
    def __str__(self):
        return self.username

views.py

class LoginForm(forms.Form):
    username = forms.CharField(
        label="用户名",
        widget=forms.TextInput,
        required=True
    )
    password = forms.CharField(
        label="密码",
        widget=forms.PasswordInput(render_value=True),
        required=True
    )
    code = forms.CharField(
        label="验证码",
        widget=forms.TextInput,
        required=True
    )
    def clean_password(self):
        pwd = self.cleaned_data.get("password")
        return md5(pwd)
def login(request):
    if request.method == 'GET':
        form = LoginForm()
        return render(request,'login.html',{"form":form})
    form = LoginForm(data=request.POST)
    if form.is_valid():
        print(form.cleaned_data) # 打印提交的数据,结果是一个字典

        user_input_code = form.cleaned_data.pop('code')  # 讲验证码从提交的数据中获取并且删除它
        code = request.session.get("image_code","")
        if user_input_code != code:
            form.add_error("code", "验证码错误")
            return render(request, 'login.html', {"form": form})

        admin_object = Admin.objects.filter(**form.cleaned_data).first()  # 数据库校验
        if not admin_object:
            form.add_error("password","用户名或密码错误")
            return render(request,'login.html',{"form":form})
        # 用户名密码正确,生成随机字符串写入到浏览器cookie 和session中
        request.session["info"] = {"id":admin_object.id,"username":admin_object.username}  # 例如当前用户名
        request.session.set_expiry(60*60*24*7) # 七天免登录
        return redirect('/adminlist')
    return render(request,'login.html',{"form":form})
# 图片验证码
from appback.util.Verification_Code import Verification_Code
from io import BytesIO
def image_code(request):
    img,code_str = Verification_Code()
    print(code_str)
    request.session["image_code"] = code_str  # 讲图片验证码写入到 session 中
    request.session.set_expiry(60)  # 设置 60s 超时
    stream = BytesIO()
    img.save(stream,'png')  # 把图片内容写入到内存中
    return HttpResponse(stream.getvalue())

图片验证码 Verification_Code.py

# 验证码  Verification Code
import random
from PIL import Image,ImageDraw,ImageFont,ImageFilter

def Verification_Code(width=120,height=30,char_length=5,font_size=28,font_file='heiti.ttf'):
    code = []
    img = Image.new(mode='RGB',size=(width,height),color=(255,255,255)) # 生成一张图片
    draw = ImageDraw.Draw(img,mode='RGB') # 生成一支画笔
    def rndChar(): # 生成随机字母
        return chr(random.randint(65,98))
    def rndColor(): # 生成随机颜色
        return (random.randint(0,255),random.randint(10,255),random.randint(64,255))

    font = ImageFont.truetype(font_file,font_size)
    for i in range(char_length): # 写文字
        char = rndChar()
        code.append(char)
        h = random.randint(0,4)
        draw.text([i * width / char_length,h],char,font=font,fill=rndColor())
    for i in range(40): # 写干扰点
        draw.point([random.randint(0,width),random.randint(0,height)],fill=rndColor())
    for i in range(40): # 写干扰圆圈
        draw.point([random.randint(0,width),random.randint(0,height)],fill=rndColor())
        x = random.randint(0, width)
        y = random.randint(0, height)
        draw.arc((x,y,x+4,y+4),0,90,fill=rndColor())
    for i in range(5): # 画干扰线
        x1 = random.randint(0,width)
        y1 = random.randint(0,height)
        x2 = random.randint(0,width)
        y2 = random.randint(0,height)

        draw.line((x1,y1,x2,y2),fill=rndColor())

    img = img.filter(ImageFilter.EDGE_ENHANCE_MORE)
    return img, "".join(code)

中间件 auth.py

from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import render,redirect,HttpResponse

class AuthMiddleware(MiddlewareMixin):
    def process_request(self,request):
        # 排除不需要登录就能访问的页面
        if request.path_info in ["/login","/image/code"]: # 获取当前用户请求的 url
            return
        # 读取当前访问用户的 session 信息
        info_dict = request.session.get("info")
        if info_dict:
            return
        # 没有登录回到登录页面
        return redirect('/login')
    def process_response(self,request,response):
        return response

md5 加密 encrpty.py

# md5 加密
from django.conf import settings
import hashlib

def md5(data_string):
    obj = hashlib.md5(settings.SECRET_KEY.encode('utf-8'))
    obj.update(data_string.encode('utf-8'))
    return obj.hexdigest()

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

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

相关文章

签完三方后无法去实习,有什么可以弥补的吗?

作者&#xff1a;阿秀校招八股文学习网站&#xff1a;https://interviewguide.cn这是阿秀的第「228」篇原创你好&#xff0c;我是阿秀。2023届秋招已经步入尾声&#xff0c;很多小伙伴都已经找到工作&签约三方&#xff0c;慢慢结束了自己的秋招之旅&#xff0c;不过也有一些…

Local Attention和动态深度卷积间的关系

摘要 Local Vision Transformer 是分别在一个个小的局部窗口中进行注意力计算。 作者将局部注意力重新定义为通道级的局部连接层&#xff08;channel-wise locally-connected layer&#xff09;&#xff0c;并4个方面进行分析&#xff1a;两种网络的正则化方式&#xff0c;稀疏…

C语言实现九大排序算法(建议收藏!)

文章目录排序算法稳定性1. 插入排序原理排序过程代码实现性能分析2. 希尔排序原理排序过程关于增量取值代码实现性能分析3. 选择排序原理排序过程代码实现性能分析4. 堆排序原理排序过程代码实现性能分析5. 冒泡排序原理排序过程代码实现性能分析6. 快速排序原理Hoare法挖坑法前…

Easy App Locker - 给你的 mac 应用加锁保护你的隐私

Easy App Locker - 给你的 mac 应用加锁保护你的隐私 Easy App Locker可以对Mac上的单个应用进行密码保护。维护Mac上的隐私。 像如果你的某个应用存在隐私数据就可以使用该软件将此应用上锁&#xff0c;这样当你的朋友使用你的 mac 时你就不用担心你的隐私被泄露了&#xff0…

Java中创建线程的五种方式

目录&#xff1a; 前言 1.进程与线程的区别&#xff1f; 2.进程是操作系统进行资源分配的基本单位&#xff0c;而操作系统是以线程为单位进行调度的。 3. Java操作多线程&#xff0c;依赖最核心的类Thread。 4.关于start和run的区别&#xff1f; 5.使用JDK自带的工具jcon…

ArcGIS基础实验操作100例--实验7分割多部分要素

本实验专栏来自于汤国安教授《地理信息系统基础实验操作100例》一书 实验平台&#xff1a;ArcGIS 10.6 实验数据&#xff1a;请访问实验1&#xff08;传送门&#xff09; 基础编辑篇--实验7 分割多部分要素 目录 一、实验背景 二、实验数据 &#xff08;1&#xff09;查看多…

第05讲:Redis主从复制

一、关于主从复制 1.1、什么是主从复制 主机数据更新后根据配置和策略&#xff0c; 自动同步到备机的master/slaver机制&#xff0c;Master以写为主&#xff0c;Slave以读为主 1.2、主从复制的作用 读写分离&#xff0c;性能扩展容灾快速恢复 二、一主多从的实验 2.1、原…

GitHub+HEXO博客设置主题

文章目录安装主题修改站点配置文件修改主题配置文件部署到github补充由于之前使用HexoGitHub搭建了个人博客用的是最原始的主题&#xff0c;丑的一批QAQ 用一下Github上面Star最高Next主题look look&#xff01; 上节博客&#xff1a;HexoGitHub搭建个人博客 主题选取网站&a…

CnOpenData中国工业企业基本信息扩展数据

一、数据简介 拉动中国经济的三个产业中&#xff0c;工业企业占有特殊的地位&#xff0c;是推动国内经济发展的重要产业。工业是最主要的物质生产部门&#xff0c;为居民生活、各行业的经济活动提供物质产品&#xff0c;这一重要作用是其他任何产业部门都无法替代的。工业企业为…

拆串后结构化,其中按行对齐

【问题】 I have a bit weired scenario where i need to fetch data i have following three products product1 product2 product3and each product has different ids(e.g. p1345,p3453,p2345) and then each froduct have different options which are having different…

算法题刷累了就来试试游戏吧----2048小游戏----C语言实现

目录 1. 代码前的准备 2. 游戏思路及代码分析 2.1 game.h 代码分析 2.2 test.cpp代码分析 3. 完整代码 3.1 game.h 3.2 game.cpp 3.3 test.cpp 嘿嘿嘿&#xff0c;写游戏还是挺高兴的撒&#xff0c;如果你还不知道2048这个小游戏的规则&#xff0c;那么快去试试吧。不然…

项目管理误区:项目不确定性≠项目风险

项目失败的原因千千万万&#xff0c;罪魁祸首肯定跟“它”脱不了关系&#xff01; 前段时间&#xff0c;偶然看到一个求助贴引发了各路网友&#xff08;项目经理&#xff09;的热议。求助人的问题是&#xff1a;“如何管理项目中的不确定性&#xff1f;” 下面的回复已然偏离答…

Linux系统运行时参数命令--文件IO性能监控

目录 4 文件IO性能监控 4.1 I/O 的两种方式(缓存 I/O 和直接 I/O) 1 缓存 I/O 2 直接 I/O 4.2 监控磁盘I/O的命令 1 iostat IO状态 2 swapon查看分区使用情况 3 df硬盘使用情况 4 du目录文件大小 4.3 文件IO写入频繁案例分析 C/CLinux服务器开发/后台架构师【零声教育…

IU8689+IU5706 单声道100W/立体声60W同步升压+功放IC大功率拉杆音箱应用组合方案

引言 目前中大功率拉杆音箱主要采用12V铅酸电池为供电电源&#xff0c;在电源直供的时候&#xff0c;一般的功放芯片输出功率在20W左右&#xff08;喇叭为4欧、THD10%&#xff09;。超过50W的功率现阶段市场上主要采用升压芯片TPA3116的组合解决方案。 随着竞争的加剧&#x…

如何进行数据可视化图表设计?

如何进行数据可视化图表设计&#xff1f; 对数据人来说&#xff0c;数据可视化是分析理解数据&#xff0c;并最终呈现数据的必修课。本文从以下几个点来说明&#xff0c;如何进行数据可视化图表设计。1、数据背后的故事2、充分理解数据3、多种图表类型设计指南 1数据背后的故…

安克创新能否锚定全球家用储能市场 隆起新的增长极?

提到能源储存&#xff0c;似乎应该是涉及一个国家或者地区的宏大概念。但事实上&#xff0c;储能正在走向家用领域。 近年来&#xff0c;全球能源价格持续高涨&#xff0c;但家用储能的成本却随着锂电等新能源技术的发展在逐渐下降&#xff0c;经济性开始凸显。家用储能在海外…

用HTML制作独一无二的2022回忆旋转相册

目录 前言 效果展示 流程 前言 元旦即将来临&#xff0c;展望2022&#xff0c;我们可以制作一个自己的2022回忆的旋转相册&#xff0c;通过下面的方法来学习吧 效果展示 制作好后&#xff0c;十张相册会在下面旋转&#xff0c;可以改为自己想要放的照片和音乐&#xff0c;制…

史上最简单的推箱子(AS3.0版)

我最熟悉的语言是 AS3.0&#xff0c;现在主要用C&#xff0c;还想学学Python&#xff0c;因此&#xff0c;最近一段时间先用AS3.0实现了最简版的推箱子、贪吃蛇和俄罗斯方块&#xff0c;然后换Python实现&#xff0c;算是熟悉了一下Python的基本用法&#xff0c;最后用C实现&a…

微信小程序 Spdier - OfferShow 反编译逆向(一)

微信小程序 Spdier - OfferShow 反编译逆向&#xff08;一&#xff09; 文章目录微信小程序 Spdier - OfferShow 反编译逆向&#xff08;一&#xff09;前言一、任务说明1.尝试反编译分析出js_code参数的生成方式&#xff0c;用来获取token2.将小程序搜索出来的数据保存至本地e…

【Java开发】Spring Cloud 01 :微服务前提精要

算是新开了一个 Spring Cloud 的坑&#xff0c;本文来源于姚半仙的《Spring Cloud 微服务项目实战》课程&#xff0c;大部分文字内容基于该课程&#xff0c;我的工作可能就是梳理归纳和拓展&#xff0c;希望尽快搞懂相对来说较为简单的 Spring Cloud Alibaba 微服务框架&#x…