乔克视界 乔克视界
首页
  • 运维
  • 开发
  • 监控
  • 安全
  • 随笔
  • Docker
  • Golang
  • Python
  • AIOps
  • DevOps
  • 心情杂货
  • 读书笔记
  • 面试
  • 实用技巧
  • 博客搭建
友链
关于
收藏
  • 分类
  • 标签
  • 归档

乔克

云原生爱好者
首页
  • 运维
  • 开发
  • 监控
  • 安全
  • 随笔
  • Docker
  • Golang
  • Python
  • AIOps
  • DevOps
  • 心情杂货
  • 读书笔记
  • 面试
  • 实用技巧
  • 博客搭建
友链
关于
收藏
  • 分类
  • 标签
  • 归档
  • Docker

  • Golang

  • AIOps

  • Python

    • 基础知识

    • Django框架

      • Django之框架
      • Django之ORM详解
      • Django之操作ORM
      • Django之操作ORM例子
      • Django之路由系统
      • Django之跨站请求伪造
      • Django之Cookie和Session
        • 一、Cookie
          • Cookie 的由来
          • Cookie 是什么
          • Cookie 的应用
          • Django 中操作 Cookie
          • 设置 Cookie
          • 获取 Cookie
          • 删除 Cookie
        • 二、Session
          • 存 Session
          • 取 Session
          • Session 优势
          • Session 缺点
          • 在 Django 中使用 Session
          • Django 中 Session 配置
          • Session 版登录验证
        • 三、Token
        • 四、CSRF_TOKEN
      • Django之CBV和FBV
      • Django之中间件
      • Django之用户认证系统
      • Django之Form组件
      • Django之Ajax
      • Django之模板语言
      • Django之URL分发
      • Django中的缓存
      • Models迁移原理
      • 自定义组件Xadmin
      • Markdown 富文本插件
      • 手写一个验证码
    • 其他

  • DevOps

  • 专栏
  • Python
  • Django框架
乔克
2025-07-19
目录

Django之Cookie和Session

# 一、Cookie

# Cookie 的由来

因为 HTTP 是无状态服务,每一次请求都是独立的,所以就用一个中间值(cookie)来记录一些用户行为。

# Cookie 是什么

Cookie 就是保存在浏览器上的键值对。

服务端控制着响应,在响应里让浏览器在本地保存 Cookie(键值对),下一次请求在发送的时候就会自动携带这个 Cookie 值。

# Cookie 的应用

1、登录,7 天免登录

2、记录用户的浏览器习惯

3、简单的投票机制

Cookie 是服务端设置的,我们浏览器可以不让服务端设置 Cookie(禁用 Cookie)。

Cookie 可以设置超时时间,如果不设置,Cookie 默认关闭浏览器就失效了。

# Django 中操作 Cookie

# 设置 Cookie
rep = HttpResponse(...)
rep = render(request, ...)

rep.set_cookie(key,value,...)
rep.set_signed_cookie(key,value,salt='加密盐', max_age=None, ...)
1
2
3
4
5

参数:

  • key, 键
  • value='', 值
  • max_age=None, 超时时间
  • expires=None, 超时时间(IE requires expires, so set it if hasn't been already.)
  • path='/', Cookie 生效的路径,/ 表示根路径,特殊的:根路径的 cookie 可以被任何 url 的页面访问
  • domain=None, Cookie 生效的域名
  • secure=False, https 传输
  • httponly=False 只能 http 协议传输,无法被 JavaScript 获取(不是绝对,底层抓包可以获取到也可以被覆盖)
# 获取 Cookie
request.COOKIES['key']
request.get_signed_cookie(key, default=RAISE_ERROR, salt='', max_age=None)
1
2

参数:

  • default: 默认值
  • salt: 加密盐
  • max_age: 后台控制过期时间
# 删除 Cookie
def logout(request):
    rep = redirect("/login/")
    rep.delete_cookie("user")  ## 删除用户浏览器上之前设置的usercookie值
    return rep
1
2
3
4

例子:views.py

from django.shortcuts import render, HttpResponse, redirect
from orm import models
from utils.mypage import Page
from functools import wraps

## Create your views here.


## 装饰器
def check_login_status(func):
    @wraps(func)
    def inner(request, *args, **kwargs):
        ## 获取cookie
        get_cookie = request.get_signed_cookie("is_login", salt="login", default=None)
        next_url = request.path_info
        if get_cookie == "123":
            return func(request, *args, **kwargs)
        else:
            return redirect("/login/?next={}".format(next_url))
    return inner


def login(request):
    """用户登录"""
    if request.method == "POST":
        user = request.POST.get("username")
        pwd = request.POST.get("password")
        ## 获取跳转url
        next_url = request.GET.get("next")
        check_username = models.Userinfo.objects.filter(username=user)
        if check_username:
            if pwd == check_username[0].password:
                if next_url:
                    ret = redirect("{}".format(next_url))
                else:
                    ret = redirect("/home/")
                ret.set_signed_cookie("is_login", "123", salt="login")
                return ret
    return render(request, "login.html")


@check_login_status
def home(request):
    return render(request, "home.html")

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45

# 二、Session

Session 是保存在服务端的键值对,它必须依赖 Cookie。

# 存 Session

1、在服务端生成随机字符串

2、生成一个和上面随机字符串对于的字典,用来保存用户的数据

3、随机字符串当 Cookie 值返回给浏览器

# 取 Session

1、从请求携带的 Cookie 中找随机字符串

2、拿到随机字符串,在 Session 中找对应的字典

3、从字典中根据 Key 取值

# Session 优势

1、比 Cookie 存的数据多

2、安全性比 Cookie 高,数据保存在服务端

# Session 缺点

1、数据量大,占用资源

# 在 Django 中使用 Session

## 获取、设置、删除Session中数据
request.session['k1']
request.session.get('k1',None)
request.session['k1'] = 123
request.session.setdefault('k1',123) ## 存在则不设置
del request.session['k1']


## 所有 键、值、键值对
request.session.keys()
request.session.values()
request.session.items()
request.session.iterkeys()
request.session.itervalues()
request.session.iteritems()

## 会话session的key
request.session.session_key

## 将所有Session失效日期小于当前日期的数据删除
request.session.clear_expired()

## 检查会话session的key在数据库中是否存在
request.session.exists("session_key")

## 删除当前会话的所有Session数据
request.session.delete()
  
## 删除当前的会话数据并删除会话的Cookie。
request.session.flush()
    这用于确保前面的会话数据不可以再次被用户的浏览器访问
    例如,django.contrib.auth.logout() 函数中就会调用它。

## 设置会话Session和Cookie的超时时间
request.session.set_expiry(value)
    * 如果value是个整数,session会在些秒数后失效。
    * 如果value是个datatime或timedelta,session就会在这个时间后失效。
    * 如果value是0,用户关闭浏览器session就会失效。
    * 如果value是None,session会依赖全局session失效策略。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39

c58d8ffb702e63dfb0e0faddfae1c332 MD5

# Django 中 Session 配置
1. 数据库Session
SESSION_ENGINE = 'django.contrib.sessions.backends.db'   ## 引擎(默认)

2. 缓存Session
SESSION_ENGINE = 'django.contrib.sessions.backends.cache'  ## 引擎
SESSION_CACHE_ALIAS = 'default'                            ## 使用的缓存别名(默认内存缓存,也可以是memcache),此处别名依赖缓存的设置

3. 文件Session
SESSION_ENGINE = 'django.contrib.sessions.backends.file'    ## 引擎
SESSION_FILE_PATH = None                                    ## 缓存文件路径,如果为None,则使用tempfile模块获取一个临时地址tempfile.gettempdir()

4. 缓存+数据库
SESSION_ENGINE = 'django.contrib.sessions.backends.cached_db'        ## 引擎

5. 加密Cookie Session
SESSION_ENGINE = 'django.contrib.sessions.backends.signed_cookies'   ## 引擎

其他公用设置项:
SESSION_COOKIE_NAME = "sessionid"                       ## Session的cookie保存在浏览器上时的key,即:sessionid=随机字符串(默认)
SESSION_COOKIE_PATH = "/"                               ## Session的cookie保存的路径(默认)
SESSION_COOKIE_DOMAIN = None                             ## Session的cookie保存的域名(默认)
SESSION_COOKIE_SECURE = False                            ## 是否Https传输cookie(默认)
SESSION_COOKIE_HTTPONLY = True                           ## 是否Session的cookie只支持http传输(默认)
SESSION_COOKIE_AGE = 1209600                             ## Session的cookie失效日期(2周)(默认)
SESSION_EXPIRE_AT_BROWSER_CLOSE = False                  ## 是否关闭浏览器使得Session过期(默认)
SESSION_SAVE_EVERY_REQUEST = False                       ## 是否每次请求都保存Session,默认修改之后才保存(默认)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# Session 版登录验证
from django.shortcuts import render, HttpResponse, redirect
from orm import models
from utils.mypage import Page
from functools import wraps
from django.views import View
from django.utils.decorators import method_decorator

## Create your views here.


## 装饰器
def check_login_status(func):
    @wraps(func)
    def inner(request, *args, **kwargs):
        ## 获取cookie
        get_cookie = request.session.get("is_login")
        next_url = request.path_info
        if get_cookie == "123":
            return func(request, *args, **kwargs)
        else:
            return redirect("/app02/login/?next={}".format(next_url))
    return inner


def login(request):
    """用户登录"""
    if request.method == "POST":
        user = request.POST.get("username")
        pwd = request.POST.get("password")
        ## 获取跳转url
        next_url = request.GET.get("next")
        check_username = models.Userinfo.objects.filter(username=user)
        if check_username:
            if pwd == check_username[0].password:
                if next_url:
                    ret = redirect("{}".format(next_url))
                else:
                    ret = redirect("/app02/home/")
                ## 设置session
                request.session["is_login"] = "123"
                return ret
    return render(request, "app02/login.html")


@check_login_status
def home(request):
    return render(request, "app02/home.html")
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47

# 三、Token

Token 也是会话保持技术,它是 Session 的增强版,拥有 Session 的所有功能,其优点是可以自定义,下面我们自定义一个 Token。

首先我们创建一个学生的模型类,如下:

class Student(models.Model):
    s_name = models.CharField(max_length=16, unique=True)
    g_name = models.ForeignKey(Grade)
    s_token = models.CharField(max_length=256)
1
2
3
4

然后我们创建一个学生注册的视图和模板:

views.py

def student_register(request):
    if request.method == "POST":
        """用户注册POST请求"""
        try:
            username = request.POST.get('username')
            grade_name = request.POST.get('grade')
            grade_obj = models.Grade.objects.get(g_name=grade_name)
            ## 注册
            models.Student.objects.create(s_name=username, g_name=grade_obj)
            return HttpResponse("注册成功")
        except Exception as e:
            print(e)
            redirect(reverse("app01:student_register"))
    ## 获取现有的班级列表
    grades = models.Grade.objects.all()
    return render(request, "student_register.html", locals())
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

student_register.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>StudentRegister</title>
</head>
<body>
<hr>
<h1>用户注册</h1>
<form action="{% url 'app01:student_register' %}" method="post">
    <button>用户名:</button>
    <input type="text" name="username" placeholder="请输入用户名">
    <br>
    <button>班级:</button>
    <select name="grade" id="">
        {% for grade in grades %}
            <option value="{{ grade.g_name }}">{{ grade.g_name }}</option>
        {% endfor %}
    </select>
    <br>
    <button>注册</button>
</form>
</body>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

然后做一个登录,登录成功->生成 Token->拿到 Token 就可以登录了。

def student_login(request):
    """用户登录"""
    print(request.META)
    if request.method == "POST":
        username = request.POST.get('username')
        grade_name = request.POST.get('grade')
        grade_obj = models.Grade.objects.get(g_name=grade_name)
        result = models.Student.objects.filter(s_name=username).filter(g_name=grade_obj)
        if result:
            ## 生成token
            try:
                ip = request.META.get("REMOTE_ADDR")
            except Exception as e:
                ip = "127.0.0.1"
            print(ip)
            token = generate_token(ip, username)
            student_obj = models.Student.objects.get(s_name=username)
            student_obj.s_token = token
            student_obj.save()
            response = HttpResponse("登录成功")
            response.set_cookie("token", token)
            return response
    grades = models.Grade.objects.all()
    return render(request, "student_login.html", locals())


def generate_token(ip, username):
    """生成token"""
    now_time = time.ctime()
    print(type(ip), type(username), type(now_time))
    return hashlib.new('md5', (ip + username + now_time).encode('utf8')).hexdigest()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

student_login.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>StudentRegister</title>
</head>
<body>
<hr>
<h1>用户注册</h1>
<form action="{% url 'app01:student_login' %}" method="post">
    <button>用户名:</button>
    <input type="text" name="username" placeholder="请输入用户名">
    <br>
    <button>班级:</button>
    <select name="grade" id="">
        {% for grade in grades %}
            <option value="{{ grade.g_name }}">{{ grade.g_name }}</option>
        {% endfor %}
    </select>
    <br>
    <button>登录</button>
</form>
</body>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

登录后就会生成一串 Token,我们就可以用这个 token 登录其他页面了。

使用 Token 就是在一些不支持浏览器 Cookie 的场景,比如手机端等。

# 四、CSRF_TOKEN

Django 中还有一种内置的 Token 叫 csrf_token,它主要是用来防跨站攻击、防恶意注册。其开启方法也很简单,只需要在我们需要 POST 请求的地方加入 csrf_token,比如如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>StudentRegister</title>
</head>
<body>
<hr>
<h1>用户注册</h1>
<form action="{% url 'app01:student_login' %}" method="post">
    {% csrf_token %}
    <button>用户名:</button>
    <input type="text" name="username" placeholder="请输入用户名">
    <br>
    <button>班级:</button>
    <select name="grade" id="">
        {% for grade in grades %}
            <option value="{{ grade.g_name }}">{{ grade.g_name }}</option>
        {% endfor %}
    </select>
    <br>
    <button>登录</button>
</form>
</body>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

这时候在第一次请求的时候就会自动生成 Token,

其流程为:

1、在我们存 csrf_token 的标签页面,响应会自动生成 cookie(csrftoken)

2、当我们提交的时候会自动验证csrftoken

3、验证通过正常执行流程,如果失败返回 403

作者:乔克

本文链接:https://jokerbai.com

版权声明:本博客所有文章除特别声明外,均采用 署名-非商业性-相同方式共享 4.0 国际 (CC-BY-NC-SA-4.0) 许可协议。转载请注明出处!

上次更新: 2025/07/19, 11:33:23
Django之跨站请求伪造
Django之CBV和FBV

← Django之跨站请求伪造 Django之CBV和FBV→

最近更新
01
使用 Generic Webhook Trigger 触发 Jenkins 多分支流水线自动化构建
07-19
02
使用Zadig从0到1实现持续交付平台
07-19
03
基于Jira的运维发布平台
07-19
更多文章>
Theme by Vdoing | Copyright © 2019-2025 乔克 | MIT License | 渝ICP备20002153号 |
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式