Django的登录校验机制
他是如何判断我之前用的是哪个id登录的呢。比如说,我之前用的user_id是王强。我使用之前登录的那个浏览器登录,他从服务器session中获取user_id,他是怎么知道获取的是这个浏览器的王强,还是另一个浏览器的张三呢。
ChatGPT 说:
ChatGPT
这个问题的关键在于 Django 的会话机制(Session Mechanism),它是通过 浏览器发送的 Cookie 来区分不同用户和浏览器的。下面分步骤解释 Django 是如何实现这一点的:
1. 浏览器中的 Cookie 关联会话
当用户登录成功后,Django 会在浏览器中设置一个名为 sessionid 的 Cookie,这个 Cookie 是唯一的,用来标识当前会话。具体过程如下:
- 用户登录成功:
- 登录视图会在服务器端创建一个会话记录,并生成一个唯一的
session_key(例如:abc123def456)。 - Django 将登录用户的 ID(如
user_id = 42)存储到服务器端会话数据中:plaintext复制代码session_key: abc123def456 session_data: {"user_id": 42} - 然后 Django 将
session_key返回给客户端,并存储在浏览器的 Cookie 中:plaintext复制代码Set-Cookie: sessionid=abc123def456; Path=/; HttpOnly
- 登录视图会在服务器端创建一个会话记录,并生成一个唯一的
- 用户下次请求:
- 当用户再次发送请求时,浏览器会自动携带之前保存的
sessionidCookie:plaintext复制代码Cookie: sessionid=abc123def456 - Django 从
sessionid中提取session_key,并根据这个session_key找到服务器端的会话数据{"user_id": 42}。
- 当用户再次发送请求时,浏览器会自动携带之前保存的
这样,Django 就能够知道这个请求是来自哪个用户,user_id = 42 即代表这个用户。
2. 不同浏览器的区别
每个浏览器的 sessionid 是独立的
- Django 会为每个新的登录会话生成一个新的
session_key,并存储在对应的浏览器的 Cookie 中。 - 这意味着:
- 如果你用浏览器 A 登录王强,浏览器 A 的
sessionid关联的是王强的会话。 - 如果你用浏览器 B 登录张三,浏览器 B 的
sessionid关联的是张三的会话。
- 如果你用浏览器 A 登录王强,浏览器 A 的
- 浏览器 A 和浏览器 B 的
sessionid是不同的,因此 Django 可以通过sessionid区分开这两个浏览器的请求。
多个用户的情况
- 如果你在同一个浏览器中登录不同的用户(比如在不同的标签页中登录),后登录的用户会覆盖之前的用户会话。这是因为浏览器的 Cookie 是全局共享的,只有一个
sessionid被存储。
3. 会话存储在服务器端
Django 会将会话数据存储在服务器端,默认是存储在数据库中(django_session 表)。存储的结构如下:
session_key | session_data | expire_date |
|---|---|---|
abc123def456 | {"user_id": 42} | 2024-01-01 00:00:00 |
xyz789ghijk | {"user_id": 57} | 2024-01-01 00:00:00 |
- Django 使用浏览器发送的
sessionid(如abc123def456)从数据库中查找到对应的session_data。 session_data中存储的user_id是 Django 用于识别用户的关键。
4. 核心流程总结
假设你用浏览器登录用户王强:
- 用户登录:
- Django 为浏览器分配一个唯一的
sessionid。 - 在服务器端会话中,
sessionid和user_id绑定(如sessionid=abc123def456->user_id=42)。 - 浏览器会保存这个
sessionid。
- Django 为浏览器分配一个唯一的
- 下次请求:
- 浏览器会自动带上
sessionid。 - Django 根据
sessionid找到会话数据,并获取user_id。 - 然后在代码中
request.session.get('user_id')返回42。
- 浏览器会自动带上
- 多个浏览器:
- 不同浏览器有不同的
sessionid,所以它们的会话数据互相独立。
- 不同浏览器有不同的
5. 示例说明
假设数据库中的会话数据:
| session_key | session_data | user_id | expire_date |
|---|---|---|---|
abc123def456 | {"user_id": 42} | 王强 | 2024-01-01 00:00:00 |
xyz789ghijk | {"user_id": 57} | 张三 | 2024-01-01 00:00:00 |
浏览器 A 的行为:
- 登录王强时,浏览器保存:plaintext复制代码
Cookie: sessionid=abc123def456 - 服务器会用
sessionid=abc123def456找到{"user_id": 42}。
浏览器 B 的行为:
- 登录张三时,浏览器保存:plaintext复制代码
Cookie: sessionid=xyz789ghijk - 服务器会用
sessionid=xyz789ghijk找到{"user_id": 57}。
6. 常见问题
1. 为什么同一浏览器中只能记录一个用户?
这是因为浏览器的 Cookie 是全局共享的,Django 只能为每个浏览器保存一个 sessionid,导致每次新的登录会覆盖旧的会话。
2. 用户会话过期时会发生什么?
如果会话过期(比如 expire_date 到期),Django 会删除对应的会话数据。
- 浏览器中仍然会携带旧的
sessionid,但 Django 找不到对应的会话,request.session会返回空。
7. 总结
Django 是通过 Cookie 的 sessionid 来识别不同浏览器和用户的。流程如下:
- 用户登录时:
- Django 为浏览器生成唯一的
sessionid,并与用户的user_id绑定,存储在服务器端。 - 浏览器保存这个
sessionid。
- Django 为浏览器生成唯一的
- 用户发送请求时:
- 浏览器携带
sessionid,Django 从会话存储中找到对应的user_id。
- 浏览器携带
- 多个浏览器:
- 每个浏览器的
sessionid是独立的,所以它们的会话互不影响。
- 每个浏览器的
通过这种机制,Django 能够区分同一服务器上的不同用户和不同浏览器。