Как показать конкретное поле только владельцу профиля пользователя в graphene-django? - PullRequest
0 голосов
/ 10 октября 2019

У меня есть следующая схема в моем приложении graphene-django:

import graphene
from django.contrib.auth import get_user_model
from graphene_django import DjangoObjectType


class UserType(DjangoObjectType):
    class Meta:
        model = get_user_model()
        fields = ("id", "username", "email")


class Query(object):
    user = graphene.Field(UserType, user_id=graphene.Int())

    def resolve_user(self, info, user_id):
        user = get_user_model().objects.get(pk=user_id)
        if info.context.user.id != user_id:
            # If the query didn't access email field -> query is ok
            # If the query tried to access email field -> raise an error
        else:
            # Logged in as the user we're querying -> let the query access all the fields

Я хочу иметь возможность запрашивать схему следующим образом:

# Logged in as user 1 => no errors, because we're allowed to see all fields
query {
  user (userId: 1) {
    id
    username
    email
  }
}

# Not logged in as user 1 => no errors, because not trying to see email
query {
  user (userId: 1) {
    id
    username
  }
}

# Not logged in as user 1 => return error because accessing email
query {
  user (userId: 1) {
    id
    username
    email
  }
}

Как я могусделать так, чтобы только вошедший в систему пользователь мог видеть поле email своего профиля, а никто другой не мог видеть электронные письма других?

1 Ответ

1 голос
/ 11 октября 2019

Вот подход, который я бы выбрал, основываясь на комментариях. Основной проблемой здесь является возможность получить список полей, запрошенных запросом в распознавателе. Для этого я использую код, адаптированный с здесь :

def get_requested_fields(info):
    """Get list of fields requested in a query."""
    fragments = info.fragments

    def iterate_field_names(prefix, field):
        name = field.name.value
        if isinstance(field, FragmentSpread):
            results = []
            new_prefix = prefix
            sub_selection = fragments[name].selection_set.selections
        else:
            results = [prefix + name]
            new_prefix = prefix + name + '.'
            sub_selection = \
                field.selection_set.selections if field.selection_set else []
        for sub_field in sub_selection:
            results += iterate_field_names(new_prefix, sub_field)
        return results

    results = iterate_field_names('', info.field_asts[0])
    return results

Остальное должно быть достаточно простым:

import graphene
from django.contrib.auth import get_user_model
from graphene_django import DjangoObjectType


class AuthorizationError(Exception):
    """Authorization failed."""


class UserType(DjangoObjectType):
    class Meta:
        model = get_user_model()
        fields = ("id", "username", "email")


class Query(object):
    user = graphene.Field(UserType, user_id=graphene.Int())

    def resolve_user(self, info, user_id):
        user = get_user_model().objects.get(pk=user_id)
        if info.context.user.id != user_id:
            fields = get_requested_fields(info)
            if 'user.email' in fields:
                raise AuthorizationError('Not authorized to access user email')
        return user
...