如何在中间件中修改django的request.user?

von4xj4u  于 2022-11-18  发布在  Go
关注(0)|答案(2)|浏览(292)

我尝试做的是检测登录用户的类型,然后将.profile参数设置为request.user,这样我就可以通过在视图中调用request.user.profile来使用它。
为此,我编写了一个Middleware,如下所示:

  1. class SetProfileMiddleware:
  2. def __init__(self, get_response):
  3. self.get_response = get_response
  4. def __call__(self, request):
  5. user, token = JWTAuthentication().authenticate(request)
  6. profile_type = token.payload.get("profile_type", None)
  7. request.user.profile = User.get_profile(profile_type, request.user)
  8. request.user.profile_type = profile_type
  9. # Works Here
  10. print("-" * 20)
  11. print(type(request.user)) # <class 'django.utils.functional.SimpleLazyObject'>
  12. print('Process Request ->', request.user.profile)
  13. response = self.get_response(request)
  14. # Does not work here
  15. print("-" * 20)
  16. print(type(request.user)) # <class 'users.models.User'>
  17. print('Process Response ->', request.user.profile)
  18. return response
  19. def process_view(self, request, view_func, view_args, view_kwargs):
  20. # Works here
  21. print("-" * 20)
  22. print(type(request.user)) # <class 'django.utils.functional.SimpleLazyObject'>
  23. print('Process View ->', request.user.profile)

现在我可以在process_view中访问request.user.profile,但它不存在于我的视图中,并导致AttributeError声明'User' object has no attribute 'profile'
似乎我的request.user是被覆盖的地方之前击中的看法。
请注意,我使用的是Django Rest框架,以下是我的观点:

  1. class ProfileAPIView(generics.RetrieveUpdateAPIView):
  2. serializer_class = ProfileSerializer
  3. def get_object(self):
  4. obj = self.request.user.profile # Raise the `AttributeError`
  5. self.check_object_permissions(self.request, obj)
  6. return obj

下面是我的settings.py

  1. MIDDLEWARE = [
  2. "django.middleware.security.SecurityMiddleware",
  3. "django.contrib.sessions.middleware.SessionMiddleware",
  4. "django.middleware.common.CommonMiddleware",
  5. "django.middleware.csrf.CsrfViewMiddleware",
  6. "django.contrib.auth.middleware.AuthenticationMiddleware",
  7. "django.contrib.messages.middleware.MessageMiddleware",
  8. "django.middleware.clickjacking.XFrameOptionsMiddleware",
  9. ]
  10. LOCAL_MIDDLEWARE = [
  11. "users.middleware.SetProfileMiddleware",
  12. ]
  13. MIDDLEWARE = MIDDLEWARE + LOCAL_MIDDLEWARE
  14. REST_FRAMEWORK = {
  15. "DEFAULT_PERMISSION_CLASSES": ("rest_framework.permissions.IsAuthenticated",),
  16. "DEFAULT_RENDERER_CLASSES": (
  17. "rest_framework.renderers.JSONRenderer",
  18. "rest_framework.renderers.BrowsableAPIRenderer",
  19. ),
  20. "DEFAULT_AUTHENTICATION_CLASSES": [
  21. "rest_framework_simplejwt.authentication.JWTAuthentication",
  22. ],
  23. }
  24. SIMPLE_JWT = {
  25. "SLIDING_TOKEN_REFRESH_LIFETIME": timedelta(minutes=45),
  26. "AUTH_TOKEN_CLASSES": ("rest_framework_simplejwt.tokens.SlidingToken",),
  27. }
  28. DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"
  29. AUTH_USER_MODEL = "users.User"
  30. LOGIN_REDIRECT_URL = "admin/"
elcex8rz

elcex8rz1#

问题是您无法将新属性添加到User类。
而是尝试将属性直接添加到请求中,如下所示
request.user_profile = User.get_profile(profile_type, request.user)

  1. def set_profile(view_function):
  2. def decorated_function(request, *args, **kwargs):
  3. user, token = JWTAuthentication().authenticate(request)
  4. profile_type = token.payload.get("profile_type", None)
  5. request.user_profile = User.get_profile(profile_type, request.user)
  6. request.user_profile_type = profile_type
  7. return view_function(request, *args, **kwargs)
  8. return decorated_function # No invocation here

然后在基于函数的视图中:

  1. @api_view(["GET", "PUT"])
  2. @set_profile
  3. def my_view(request):
  4. request.user_profile # Will not throw attribute error
  5. ...

基于函数的视图和基于类的视图之间的唯一区别是装饰器将接收request参数而不是self

  1. def set_profile(view_function):
  2. def decorated_function(self, *args, **kwargs):
  3. user, token = JWTAuthentication().authenticate(self.request)
  4. profile_type = token.payload.get("profile_type", None)
  5. self.request.user_profile = User.get_profile(profile_type, self.request.user)
  6. self.request.user_profile_type = profile_type
  7. return view_function(self, *args, **kwargs)
  8. return decorated_function # No invocation here

您的类应如下所示:

  1. class ProfileAPIView(generics.RetrieveUpdateAPIView):
  2. serializer_class = ProfileSerializer
  3. @set_profile
  4. def get_object(self):
  5. obj = self.request.user_profile
  6. self.check_object_permissions(self.request, obj)
  7. return obj
展开查看全部
lrpiutwd

lrpiutwd2#

在花了几个小时弄清楚发生了什么之后,发现SimpleJWTJWTAuthentication.authenticate()方法在请求到达视图之前被调用,覆盖了request.user属性。
因此,我没有尝试使用中间件将概要文件添加到request.user,而是结束了对JWTAuthentication.authentication()方法的定制:

  1. class CustomAuth(JWTAuthentication):
  2. def authenticate(self, request):
  3. user, token = super().authenticate(request)
  4. profile_type = token.payload.get("profile_type", None)
  5. user.profile = User.get_profile((profile_type, user)
  6. user.profile_type = profile_type
  7. return user, token

settings.py

  1. REST_FRAMEWORK = {
  2. "DEFAULT_AUTHENTICATION_CLASSES": [
  3. "users.authentication.CustomAuth"
  4. ],
  5. }
展开查看全部

相关问题