【问题标题】:DRF - How to Authentify an application with Oauth Toolkit?DRF - 如何使用 Oauth Toolkit 验证应用程序?
【发布时间】:2018-07-02 15:46:21
【问题描述】:

在我的应用程序中,我使用了修改后的 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 参数,用户必须在我的一个应用上付费。

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

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

【问题讨论】:

  • 您的问题标题似乎与您的问题正文不匹配。你确定它准确吗?

标签: python django rest oauth django-rest-framework


【解决方案1】:

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

例如,您为您的 ios 应用程序生成了一个令牌 abcd。您的 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

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

【讨论】:

  • 嗬,很好,我想我会这样做的。我会接受@Andrea 的回答,因为它回答了我一半的问题,并给你赏金
【解决方案2】:

如果我对问题的理解正确,您希望某个字段 (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',)

在这里,如您所见,两个序列化程序之间的唯一区别是RestrictedUserSerializer.Meta 中存在read_only_fields 属性。

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

class UserViewSet(viewsets.ModelViewSet):

    def get_serializer_class(self):
        if is_third_party_app(self.request.user):
            return UserSerializer
        return RestrictedUserSerializer

    # ...

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

【讨论】:

  • 哦,这是一个很好的方法,我没有想到嵌​​套序列化程序,非常感谢。但事实上这是我问题的一半,因为我最麻烦的部分是如何实现is_third_party_app() 函数。 (因此我的问题标题是“如何验证应用程序?”)
猜你喜欢
  • 2015-08-31
  • 2015-08-30
  • 2022-11-11
  • 1970-01-01
  • 2019-06-19
  • 2012-05-10
  • 1970-01-01
  • 2020-08-31
  • 2012-05-01
相关资源
最近更新 更多