暗黑模式
Request
Request.user
形成过程
在 Django REST Framework (DRF) 中,rest_framework.request.Request.user
表示当前请求的用户对象,它是通过 DRF 的认证流程动态赋值的。以下是它的形成过程的详细解析:
形成过程
请求到达 Django
- 当客户端发送请求时,Django 会创建一个
HttpRequest
对象来表示该请求。 - DRF 在此基础上扩展并包装了 Django 的
HttpRequest
对象,生成一个rest_framework.request.Request
对象。
- 当客户端发送请求时,Django 会创建一个
认证类介入
- DRF 的认证机制通过认证类(
Authentication
classes)来验证请求,并尝试确定用户的身份。 - 认证类的行为由
settings.py
中的DEFAULT_AUTHENTICATION_CLASSES
配置决定:pythonREST_FRAMEWORK = { 'DEFAULT_AUTHENTICATION_CLASSES': ( 'rest_framework.authentication.SessionAuthentication', 'rest_framework.authentication.TokenAuthentication', ), }
1
2
3
4
5
6
- DRF 的认证机制通过认证类(
调用认证类的
authenticate()
方法- DRF 会按照配置的顺序调用认证类的
authenticate()
方法。 - 如果某个认证类验证成功,它会返回两个值:
(user, auth)
,其中:user
: 当前请求的用户对象。auth
: 认证信息(如令牌或会话对象)。
- DRF 会按照配置的顺序调用认证类的
赋值给
Request.user
- DRF 的请求处理流程会将返回的
user
对象赋值给Request.user
,以便后续在视图或权限类中使用。
- DRF 的请求处理流程会将返回的
未认证用户的处理
- 如果所有认证类均未返回有效的用户对象,
Request.user
会被设置为AnonymousUser
。
- 如果所有认证类均未返回有效的用户对象,
核心代码分析
DRF 的认证流程
认证逻辑主要在 rest_framework.request.Request
类中:
Request
类的user
属性:python@cached_property def user(self): """ Returns the user associated with the current request, as authenticated by the authentication classes. """ if not hasattr(self, '_user'): self._authenticate() return self._user
1
2
3
4
5
6
7
8
9调用
_authenticate()
方法:pythondef _authenticate(self): """ Attempt to authenticate the request using the configured authentication classes. """ for authenticator in self.authenticators: try: user_auth_tuple = authenticator.authenticate(self) except exceptions.APIException: self._not_authenticated() raise if user_auth_tuple is not None: self._user, self._auth = user_auth_tuple return self._not_authenticated()
1
2
3
4
5
6
7
8
9
10
11
12
13
14如果认证失败:
pythondef _not_authenticated(self): self._user = AnonymousUser() self._auth = None
1
2
3
总结
Request.user
的值来源于认证类的authenticate()
方法返回值。- 未通过认证时,默认值为
AnonymousUser
。
认证类的具体行为
1. SessionAuthentication
- 基于 Django 的会话机制验证用户。
- 检查请求中的会话 Cookie,尝试恢复用户:python
def authenticate(self, request): user = getattr(request._request, 'user', None) if not user or not user.is_authenticated: return None return (user, None)
1
2
3
4
5
2. TokenAuthentication
- 使用令牌(Token)验证用户。
- 检查请求头中的
Authorization
字段,解析令牌并返回用户:pythondef authenticate(self, request): auth = get_authorization_header(request).split() if auth and auth[0].lower() == b'token': token = auth[1].decode() user = self.authenticate_credentials(token) return (user, token) return None
1
2
3
4
5
6
7
3. 自定义认证类
- 你可以创建自己的认证类,继承
BaseAuthentication
并实现authenticate()
方法。 - 示例:python
from rest_framework.authentication import BaseAuthentication class MyCustomAuthentication(BaseAuthentication): def authenticate(self, request): # 自定义认证逻辑 user = get_user_from_custom_header(request) if user: return (user, None) return None
1
2
3
4
5
6
7
8
9
验证 Request.user 的值
示例视图
python
from rest_framework.views import APIView
from rest_framework.response import Response
class ExampleView(APIView):
def get(self, request):
if request.user.is_authenticated:
return Response({"message": f"Hello, {request.user.username}!"})
return Response({"message": "Hello, Anonymous!"})
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
测试结果
使用认证用户请求:
- 登录后请求,
Request.user
是认证的用户对象。 - 响应:json
{"message": "Hello, john_doe!"}
1
- 登录后请求,
匿名用户请求:
- 未登录的请求,
Request.user
是AnonymousUser
。 - 响应:json
{"message": "Hello, Anonymous!"}
1
- 未登录的请求,
总结
- 来源:
Request.user
的值通过 DRF 的认证类生成,主要依赖authenticate()
方法的返回结果。 - 值的类型:
- 成功认证:为
User
对象(django.contrib.auth.models.User
或自定义用户模型)。 - 未认证:为
AnonymousUser
。
- 成功认证:为
- 为何重要:
Request.user
是 DRF 视图和权限类中使用用户信息的标准方式,是权限和认证系统的核心。
通过了解认证类的行为和 DRF 的认证流程,可以灵活调整 Request.user
的来源和行为以满足特定需求。
Request.user
实时性
在 Django REST Framework (DRF) 中,Request.user
的值是否实时从数据库中获取取决于认证类和具体的实现。以下是详细的行为分析:
1. Request.user
的生成机制
当 DRF 处理请求时,Request.user
的值由认证类的 authenticate()
方法返回,并赋值给 Request.user
。认证类通常根据请求中的认证信息(如会话 Cookie、Token)来加载用户。
对于
SessionAuthentication
:Request.user
是从 Django 的会话数据中恢复的。- 恢复的用户对象是通过 Django 的认证系统(
django.contrib.auth.get_user()
)加载的。 - 行为:
- 每次请求会检查会话并加载对应的用户对象。
- 如果用户在会话存储中的数据被修改,
Request.user
会反映这些更改,因为它是从数据库中动态加载的。
对于
TokenAuthentication
:Request.user
是通过 Token 查找用户。- 行为:
- 根据请求头中的 Token,调用
Token.objects.get()
查找用户。 - 如果用户的数据(如权限)被修改,
Request.user
会根据数据库中的最新数据重新加载。
- 根据请求头中的 Token,调用
2. Request.user
的缓存机制
DRF 的实现细节
Request.user
是一个 @cached_property
,这意味着在同一个请求的生命周期中,它只会被计算一次。
python
@cached_property
def user(self):
"""
Returns the user associated with the current request, as authenticated
by the authentication classes.
"""
if not hasattr(self, '_user'):
self._authenticate()
return self._user
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
第一次访问
Request.user
:- 调用
_authenticate()
方法,加载用户对象。 - 认证类返回的用户对象会被缓存到
_user
属性中。
- 调用
后续访问
Request.user
:- 直接返回缓存的
_user
,不会重复查询数据库。
- 直接返回缓存的
是否实时从数据库获取?
- 在同一个请求的生命周期中,
Request.user
不会重复查询数据库,它使用缓存的用户对象。 - 在每个新的请求中,DRF 会重新运行认证逻辑,从认证类获取用户对象,因此 新请求会反映数据库的最新状态。
3. 数据库中用户信息的实时性
在某些情况下,Request.user
的数据可能与数据库不一致:
缓存的用户对象未刷新
- 如果用户对象在请求中已被加载并缓存,但在同一请求的生命周期中数据库发生了更改,
Request.user
不会自动反映这些更改。 - 解决方法:重新加载用户对象。python
user = request.user user.refresh_from_db() # 从数据库刷新用户数据
1
2
- 如果用户对象在请求中已被加载并缓存,但在同一请求的生命周期中数据库发生了更改,
全局用户数据的变更
- 如果用户在请求之间的时间内发生了更改(例如修改了权限或信息),新请求会从数据库中加载最新数据。
4. 示例行为
示例 1:修改用户的权限
假设你有以下视图代码:
python
from rest_framework.views import APIView
from rest_framework.response import Response
class ExampleView(APIView):
def get(self, request):
return Response({
"username": request.user.username,
"is_superuser": request.user.is_superuser,
})
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
请求 1:加载用户信息
- 用户
john
不是超级用户。 - 响应:json
{ "username": "john", "is_superuser": false }
1
2
3
4
- 用户
请求之间修改用户权限
- 在后台将用户
john
设置为超级用户。
- 在后台将用户
请求 2:检查最新权限
- 新的请求会重新从数据库加载用户。
- 响应:json
{ "username": "john", "is_superuser": true }
1
2
3
4
示例 2:在同一个请求中修改用户数据
如果在请求中修改了用户对象,但未刷新数据库:
python
class ModifyUserView(APIView):
def get(self, request):
request.user.is_superuser = True
return Response({
"username": request.user.username,
"is_superuser": request.user.is_superuser,
})
1
2
3
4
5
6
7
2
3
4
5
6
7
- 响应:json
{ "username": "john", "is_superuser": true }
1
2
3
4 - 数据库中的用户对象不会反映这些更改,除非调用
save()
。
5. 认证类的影响
SessionAuthentication
- 用户对象基于会话数据加载,通常由 Django 的
AuthenticationMiddleware
提供。 - 每次请求都会检查会话,但
Request.user
在同一个请求中只加载一次。
TokenAuthentication
- 用户对象基于 Token 加载,每次请求会查询对应的用户。
Request.user
在认证成功后只加载一次。
6. 如何确保实时性?
如果你需要确保在某些情况下用户信息是实时的,可以采取以下措施:
刷新用户对象: 在处理逻辑中手动刷新用户数据:
pythonrequest.user.refresh_from_db()
1避免缓存用户对象: 如果你需要频繁获取用户的实时状态,可以在每次访问时重新加载用户对象:
pythonuser = User.objects.get(pk=request.user.pk)
1使用中间件更新数据: 如果需要在整个请求处理中始终使用最新用户信息,可以通过中间件强制刷新用户对象。
7. 总结
- 同一个请求生命周期中:
Request.user
使用缓存的用户对象,不会多次查询数据库。 - 新请求:DRF 会通过认证类从数据库重新加载用户,反映数据库的最新状态。
- 手动刷新:在需要实时更新用户信息的场景,可以调用
refresh_from_db()
。 - 结合场景选择:在性能和实时性之间找到平衡点,避免不必要的频繁数据库查询。
Request.user
自定义模型和字段
在 Django 中,request.user
通常是 Django 的用户模型(User
)的实例,具体字段取决于你使用的用户模型。
以下是 默认用户模型(django.contrib.auth.models.User
) 提供的字段。如果你使用的是自定义用户模型,这些字段可能会有所不同。
1. 默认用户模型 (User
) 的字段
Django 的默认用户模型是 django.contrib.auth.models.User
。以下是它的主要字段:
字段名称 | 描述 |
---|---|
id | 用户的唯一标识符(主键)。 |
username | 用户名,必须唯一,默认最大长度为 150 个字符。 |
password | 哈希格式存储的用户密码。 |
first_name | 用户的名字,可选字段。 |
last_name | 用户的姓氏,可选字段。 |
email | 用户的电子邮件地址,可选字段。 |
is_staff | 布尔值,表示用户是否有权限登录管理后台。 |
is_active | 布尔值,表示用户账户是否被激活。 |
is_superuser | 布尔值,表示用户是否是超级用户。 |
last_login | 用户上一次登录的时间,自动更新。 |
date_joined | 用户账户的创建时间。 |
2. 默认用户模型的属性和方法
除了字段外,request.user
还提供了一些常用的属性和方法,用于处理用户认证、权限和其他操作。
认证相关
属性/方法 | 描述 |
---|---|
is_authenticated | 布尔值,表示用户是否通过认证。 |
is_anonymous | 布尔值,表示用户是否是匿名用户(未认证用户)。 |
权限相关
属性/方法 | 描述 |
---|---|
has_perm(perm) | 检查用户是否有指定的权限(如 "app_name.permission_name" )。 |
has_perms(perms) | 检查用户是否有一组权限(如 ["app_name.permission1", "app_name.permission2"] )。 |
has_module_perms(app_label) | 检查用户是否有指定应用程序的任何权限。 |
其他方法
方法 | 描述 |
---|---|
get_full_name() | 返回用户的完整名称,格式为 "first_name last_name" 。 |
get_short_name() | 返回用户的名字(first_name )。 |
set_password(raw_password) | 设置用户的密码,自动生成哈希格式。 |
check_password(raw_password) | 检查用户的密码是否匹配存储的哈希值。 |
3. 自定义用户模型
如果你使用了自定义用户模型(通过 AUTH_USER_MODEL
设置),request.user
的字段将取决于你的自定义模型。
如何查看字段?
可以通过 Django 的 inspectdb
或 Python 的内置方法查看字段:
python
# 获取用户模型
from django.contrib.auth import get_user_model
User = get_user_model()
# 查看所有字段
print(User._meta.get_fields())
1
2
3
4
5
6
2
3
4
5
6
自定义用户模型示例
python
from django.contrib.auth.models import AbstractUser
from django.db import models
class CustomUser(AbstractUser):
phone_number = models.CharField(max_length=15, blank=True, null=True)
address = models.TextField(blank=True, null=True)
1
2
3
4
5
6
2
3
4
5
6
在这种情况下,request.user
还会包含 phone_number
和 address
字段。
4. 如何访问这些字段
在 Django 视图或模板中,你可以通过以下方式访问 request.user
的字段或属性:
在视图中
python
from rest_framework.views import APIView
from rest_framework.response import Response
class UserDetailView(APIView):
def get(self, request):
user = request.user
return Response({
"id": user.id,
"username": user.username,
"email": user.email,
"is_authenticated": user.is_authenticated,
"is_staff": user.is_staff,
})
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
在模板中
html
<p>Username: {{ request.user.username }}</p>
<p>Email: {{ request.user.email }}</p>
<p>Is Staff: {{ request.user.is_staff }}</p>
1
2
3
2
3
5. 匿名用户 (AnonymousUser
) 的字段
如果用户未通过认证,request.user
是一个 AnonymousUser
实例,而不是 User
实例。
AnonymousUser 的主要字段和属性
字段/属性 | 描述 |
---|---|
is_authenticated | 恒为 False 。 |
is_anonymous | 恒为 True 。 |
username | 返回空字符串 "" 。 |
示例:
python
if request.user.is_authenticated:
print(f"Welcome, {request.user.username}")
else:
print("You are not logged in.")
1
2
3
4
2
3
4
6. 总结
- 默认字段:
request.user
的字段主要来源于 Django 的默认用户模型,包括username
、email
、is_staff
等。 - 动态扩展:如果你使用自定义用户模型,
request.user
的字段将根据你的模型定义动态扩展。 - 认证状态:
is_authenticated
和is_anonymous
是判断用户认证状态的关键属性。 - 匿名用户:未认证时,
request.user
是一个AnonymousUser
,其字段和方法非常有限。
在实际开发中,可以通过 get_user_model()
动态获取用户模型,确保代码适应自定义用户模型的扩展性。