Jor*_*dan 29 python django django-rest-framework
我正在尝试制作中间件,根据子域等改变用户的某些字段......
唯一的问题是request.user总是在中间件中作为AnonymousUser提供,但是在视图中是正确的用户.我已经离开了django在设置中使用的默认身份验证和会话中间件.
这里有一个类似的问题:Django,request.user总是匿名用户 但是没有过度回答整个问题,因为我没有使用不同的身份验证方法,并且在调用我自己的中间件之前djangos身份验证正在运行.
有没有办法在使用DRF时获取中间件中的request.user?我将在这里展示一些示例代码:
class SampleMiddleware(object):
def process_view(self, request, view_func, view_args, view_kwargs):
#This will be AnonymousUser. I need it to be the actual user making the request.
print (request.user)
def process_response(self, request, response):
return response
Run Code Online (Sandbox Code Playgroud)
使用process_request:
class SampleMiddleware(object):
def process_request(self, request):
#This will be AnonymousUser. I need it to be the actual user making the request.
print (request.user)
def process_response(self, request, response):
return response
Run Code Online (Sandbox Code Playgroud)
Jor*_*dan 31
嘿伙计我通过从请求中获取DRF令牌并将request.user加载到与该模型关联的用户来解决此问题.
我有默认的django身份验证和会话中间件,但似乎DRF在中间件解析用户之后使用它的令牌身份验证(所有请求都是CORS请求,这可能就是原因).这是我更新的中间件类:
from re import sub
from rest_framework.authtoken.models import Token
from core.models import OrganizationRole, Organization, User
class OrganizationMiddleware(object):
def process_view(self, request, view_func, view_args, view_kwargs):
header_token = request.META.get('HTTP_AUTHORIZATION', None)
if header_token is not None:
try:
token = sub('Token ', '', request.META.get('HTTP_AUTHORIZATION', None))
token_obj = Token.objects.get(key = token)
request.user = token_obj.user
except Token.DoesNotExist:
pass
#This is now the correct user
print (request.user)
Run Code Online (Sandbox Code Playgroud)
这也可以在process_view或process_request上使用.
希望这可以在将来帮助某人.
Dan*_*ski 18
遇到同样的问题,今天遇到了这个问题.
TL; DR;
跳过下面的代码示例
说明
事情是DRF有自己的事物流,正好在django请求生命周期的中间.
因此,如果正常的中间件流程是:
DRF代码覆盖默认的django视图代码,并执行自己的代码.
在上面的链接中,您可以看到它们使用自己的方法包装原始请求,其中一种方法是DRF身份验证.
回到你的问题,这就是request.user在中间件中使用是不成熟的原因,因为它只在 view_middleware**执行后得到它的值.
我使用的解决方案是让我的中间件设置为LazyObject.这有帮助,因为我的代码(实际的DRF ApiVIew)在DRF的身份验证已经设置了实际用户时执行.这里提出了这个解决方案和讨论.
如果DRF有更好的方法来扩展其功能,可能会更好,但事实上,这似乎比提供的解决方案更好(性能和可读性都明智).
代码示例
from django.utils.functional import SimpleLazyObject
def get_actual_value(request):
if request.user is None:
return None
return request.user #here should have value, so any code using request.user will work
class MyCustomMiddleware(object):
def process_request(self, request):
request.custom_prop = SimpleLazyObject(lambda: get_actual_value(request))
Run Code Online (Sandbox Code Playgroud)
hoe*_*ing 12
接受的答案仅考虑TokenAuthentication- 就我而言,配置了更多身份验证方法。因此,我直接初始化 DRF Request,这会调用 DRF 的身份验证机制并循环遍历所有配置的身份验证方法。
不幸的是,它仍然给数据库带来了额外的负载,因为Token必须查询对象(接受的答案也有这个问题)。这个答案SimpleLazyObject中的技巧是一个更好的解决方案,但它不适用于我的用例,因为我直接需要中间件中的用户信息 - 我正在扩展指标并在调用之前处理请求。django_prometheusget_response
from rest_framework.request import Request as RestFrameworkRequest
from rest_framework.views import APIView
class MyMiddleware:
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
drf_request: RestFrameworkRequest = APIView().initialize_request(request)
user = drf_request.user
...
return self.get_response(request)
Run Code Online (Sandbox Code Playgroud)
基于上面 Daniel Dubovski 非常优雅的解决方案,这里有一个 Django 1.11 的中间件示例:
from django.utils.functional import SimpleLazyObject
from organization.models import OrganizationMember
from django.core.exceptions import ObjectDoesNotExist
def get_active_member(request):
try:
active_member = OrganizationMember.objects.get(user=request.user)
except (ObjectDoesNotExist, TypeError):
active_member = None
return active_member
class OrganizationMiddleware(object):
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
# Code to be executed for each request before
# the view (and later middleware) are called.
request.active_member = SimpleLazyObject(lambda: get_active_member(request))
response = self.get_response(request)
# Code to be executed for each request/response after
# the view is called.
return response
Run Code Online (Sandbox Code Playgroud)
在大多数情况下,丹尼尔·杜博夫斯基的解决方案可能是最好的。
惰性对象方法的问题是您是否需要依赖副作用。就我而言,无论如何,我都需要为每个请求发生一些事情。
如果我使用像 这样的特殊值request.custom_prop,则必须针对每个请求进行评估,以免产生副作用。我注意到其他人正在设置request.user,但它对我不起作用,因为某些中间件或身份验证类会覆盖此属性。
如果 DRF 支持自己的中间件怎么办?我可以在哪里插入它?在我的例子中,最简单的方法(我不需要访问对象request,只需要访问经过身份验证的用户)似乎是挂钩到身份验证类本身:
from rest_framework.authentication import TokenAuthentication
class TokenAuthenticationWithSideffects(TokenAuthentication):
def authenticate(self, request):
user_auth_tuple = super().authenticate(request)
if user_auth_tuple is None:
return
(user, token) = user_auth_tuple
# Do stuff with the user here!
return (user, token)
Run Code Online (Sandbox Code Playgroud)
然后我可以在我的设置中替换这一行:
REST_FRAMEWORK = {
"DEFAULT_AUTHENTICATION_CLASSES": (
#"rest_framework.authentication.TokenAuthentication",
"my_project.authentication.TokenAuthenticationWithSideffects",
),
# ...
}
Run Code Online (Sandbox Code Playgroud)
我不是在推广这个解决方案,但也许它会对其他人有所帮助。
优点:
缺点:
| 归档时间: |
|
| 查看次数: |
15114 次 |
| 最近记录: |