2

我正在开发一个基于 DRF 的应用程序,需要 LDAP 身份验证。我遇到了一个问题,我看到直接通过 DRF API 登录的用户和从外部应用程序(即 Curl/Postman)访问它的用户的不同行为。

在应用程序中,一旦登录,我会提供一系列用户可以访问的视图/url,即下面的 url 以查看“示例”:

http://:8000/api/samples

我已经使用自定义权限类将 DjangoModelPermissions 应用于我的示例视图,该视图需要模型权限才能查看模型,即:

class HasModelPermission(permissions.DjangoModelPermissions):
    perms_map = {
        'GET': ['%(app_label)s.read_%(model_name)s'],
        'OPTIONS': ['%(app_label)s.read_%(model_name)s'],
        'HEAD': ['%(app_label)s.read_%(model_name)s'],
        'POST': ['%(app_label)s.add_%(model_name)s'],
        'PUT': ['%(app_label)s.change_%(model_name)s'],
        'PATCH': ['%(app_label)s.change_%(model_name)s'],
        'DELETE': ['%(app_label)s.delete_%(model_name)s'],
    }

class SampleView(generics.ListAPIView):
    queryset = Sample.objects.all()
    serializer_class = SampleSerializer
    permission_classes = [HasModelPermission]

根据https://django-auth-ldap.readthedocs.io/en/latest/permissions.html#group-mirroring,我已经使用 AUTH_LDAP_FIND_GROUP_PERMS=true 配置了我的 ldap 设置,并为我关心的 LDAP 组创建了匹配的 DJANGO 组关于 - 我已经为这些组分配了模型权限。这正如我所期望的那样工作 - 只有具有查看列表权限的组成员的用户才能看到它。

我看到的关键问题是,虽然内部 DRF API 正确确定用户权限,但外部登录然后提交 GET 请求的用户被确定为没有查看权限。

我通过一些调试确定原因是来自django_auth_ldap.backend.py的以下代码中的测试失败,该代码从DRF 中的视图调度程序调用,本质上,当我从 DRF API 中的内置访问 URL 时,“hasattr( user, 'ldap_user'):" 返回 true,当我通过邮递员或 curl 等连接时,"hasattr(user, 'ldap_user'):" 返回 false - 显然意味着没有确定存在用户权限。

def get_group_permissions(self, user, obj=None):
    if not hasattr(user, 'ldap_user') and self.settings.AUTHORIZE_ALL_USERS:
        _LDAPUser(self, user=user)  # This sets user.ldap_user

    if hasattr(user, 'ldap_user'):
        permissions = user.ldap_user.get_group_permissions()
    else:
        permissions = set()

    return permissions

所以我想最终我的问题是,我应该如何在来自远程端点的 HTTP 操作之间填充/维护 user.ldap_user 属性。(注意我使用的是会话和令牌认证 ATM)。我猜我的问题更多地与在操作之间维护用户 lda_user 属性数据有关,或者能够在每个连续操作中检索它。

4

2 回答 2

0

我有同样的错误并用 django_auth_ldap LDAPackend 修复它。

我也有自己的 Token 模型;这是简短的版本:

from django_auth_ldap.backend import LDAPBackend
from rest_framework import authentication
from users.models import Token

class TokenAuthentication(authentication.TokenAuthentication):
    def authenticate_credentials(self, key):
        token = Token.objects.prefetch_related('user').get(key=key)
       
        ldap_backend = LDAPBackend()
        user = ldap_backend.populate_user(token.user.username)
        if user:
            return user, token

        return token.user, token
于 2021-10-20T14:13:26.077 回答
0

通过设置AUTH_LDAP_AUTHORIZE_ALL_USERS = True,您将验证所有请求(还有 curl/postman 请求)。

如果您只希望它用于您的令牌身份验证端点(开销低于populate_user()),您可以选择:

class TokenAuthentication(TokenAuthentication):
    def authenticate(self, request):
        # authenticate user
        user, token = super().authenticate(request)

        # set user.ldap_user
        _LDAPUser(LDAPBackend(), user=user)

        # or:
        # user = LDAPBackend().get_user(user.id)

       return user, token

与缓存一起使用很有用:AUTH_LDAP_CACHE_TIMEOUT

于 2021-12-07T17:13:16.537 回答