代码之家  ›  专栏  ›  技术社区  ›  Elio Maisonneuve

DRF-如何使用Oauth Toolkit对应用程序进行身份验证?

  •  4
  • Elio Maisonneuve  · 技术社区  · 8 年前

    在我的应用程序中,我使用修改后的 User 模型中还有3个我需要的字段。

    from django.contrib.auth.models import AbstractUser
    from django.db import models
    
    import ldapdb.models
    
    
    class User(AbstractUser):
        cotisant = models.BooleanField(default=False)
        nbSessions = models.IntegerField(default=0)
        tel = models.CharField(max_length=20, default="")
    

    我希望人们能够更改他们的帐户设置(如密码、电子邮件、, tel ,...).

    为此,我有这样一个序列化程序:

    from rest_framework import serializers
    from django.contrib.auth.hashers import make_password
    from coreapp.models import User
    
    
    class UserSerializer(serializers.ModelSerializer):
        class Meta:
            model = User
            fields = ('username', 'first_name', 'last_name', 'email', 'password', 'cotisant', 'tel')
            extra_kwargs = {
                # Allow to set pwd, but disallow getting the hash from database
                'password': {'write_only': True}
            }
    
        def validate_password(self, value: str):
            return make_password(value)
    

    还有这样一种观点:

    class UserViewSet(viewsets.ModelViewSet):
        serializer_class = UserSerializer
        permission_classes = (IsSelfOrStaffPermission, TokenHasReadWriteScopeOrCreate,)
        lookup_field = 'username'
    
        def get_queryset(self):
            current_user = self.request.user
            if current_user.is_staff:
                user_set = User.objects.all()
            else:
                user_set = User.objects.filter(username=current_user.username)
    
            query = self.request.query_params.get('q', None)
    
            if not query:
                return user_set
    
            return user_set.filter(
                Q(username__icontains=query) |
                Q(first_name__icontains=query) |
                Q(last_name__icontains=query)
            )
    

    (这只允许用户自己访问,除非他是员工)

    问题是 nbSessions 参数,用户必须在我的一个应用程序上支付一些费用。

    如何允许应用程序设置参数,但不允许用户直接更新?

    注意:我有其他使用密码凭据流的应用程序,它们是客户端,所以有人可以通过它获取应用令牌。

    2 回复  |  直到 8 年前
        1
  •  1
  •   Andrea Corbellini    8 年前

    如果我理解正确的话,你需要一个特定的字段( nbSessions )某些第三方应用程序可通过相同的API端点写入,但普通用户无法写入。

    我将这样做:创建两个不同的序列化程序,一个用于第三方应用程序,另一个用于普通用户。

    class UserSerializer(serializers.ModelSerializer):
        """
        Serializer used by third-party apps.
        All fields, including nbSessions, are writeable.
        """
    
        class Meta:
            model = User
            fields = ('username', 'first_name', 'last_name', 'email', 'password', 'cotisant', 'nbSessions', 'tel')
            extra_kwargs = {
                'password': {'write_only': True}
            }
    
        # ...
    
    class RestrictedUserSerializer(UserSerializer):
        """
        Serializer used by regular users.
        All fields except nbSessions are writeable.
        It inherits from UserSerializer so that common code is not duplicated.
        """
    
        class Meta(BaseUserSerializer.Meta):
            read_only_fields = ('nbSessions',)
    

    在这里,您可以看到,这两个序列化程序之间的唯一区别是 read_only_fields 中的属性 RestrictedUserSerializer.Meta .

    然后,在您的视图中,您可以检查您的请求,以查看要使用的序列化程序类:

    class UserViewSet(viewsets.ModelViewSet):
    
        def get_serializer_class(self):
            if is_third_party_app(self.request.user):
                return UserSerializer
            return RestrictedUserSerializer
    
        # ...
    

    您可以进一步扩展此概念,并为普通用户、第三方应用程序、职员、管理员等提供不同的序列化程序类(可能继承自同一基类)。每个序列化程序都可以有其特定的字段集、验证规则和更新逻辑。

        2
  •  1
  •   zaphod100.10    8 年前

    您必须使用客户端机密来识别谁在调用您的api。您必须为客户端生成api密钥。客户端将这些api密钥作为查询参数发送,以证明它们是您批准的客户端。

    例如,您生成了一个令牌 abcd 用于ios应用程序。您的ios应用程序将通过以下方式发送请求: https://your-endpoint.com/api/method/?token=abcd

    要检查令牌是否正确,可以创建自定义权限类。

    class IsApprovedClientPermission(permissions.BasePermission):
    
        def has_permission(self, request, view):
            token = request.query_params.get('token', None)
            if request.method not in permissions.SAFE_METHODS:
                # custom checks
                return token in approved_tokens_list:
            return True
    

    在允许请求修改数据之前,可以将此权限类应用于要验证的任何视图。