Giter VIP home page Giter VIP logo

django-graph-auth's Introduction

django-graph-auth

django-graph-auth is a Django application which provides simple mutations and queries for managing users with GraphQL. It can register users, log in, reset users, and expose JSON web tokens.

Documentation can be found on GitHub.

Requirements

This has only been tested with:

  • Python: 3.5
  • Django: 1.10

Setup

Install from pip:

pip install django-graph-auth

and then add it to your installed apps:

INSTALLED_APPS = (
    ...
    'graph_auth',
    ...
)

You will also need to edit your base schema to import the mutations and queries, like this:

import graphene
from graphene import relay, ObjectType

import graph_auth.schema

class Query(graph_auth.schema.Query, ObjectType):
    node = relay.Node.Field()

class Mutation(graph_auth.schema.Mutation, ObjectType):
    pass

schema = graphene.Schema(query=Query, mutation=Mutation)

Optional Settings

GRAPH_AUTH = {
    'USER_FIELDS': ('email', 'first_name', 'last_name', ), # Which user fields are available
    'ONLY_ADMIN_REGISTRATION': False, # Only alow admins to register new users
    'WELCOME_EMAIL_TEMPLATE': None, # Email template for optional welcome email, user object fields is in scope
    'EMAIL_FROM': None # Email from for welcome email
}

Credits

django-graph-auth was created by Morgante Pell (@morgante) and Anthony Loko (@amelius15). It is based on django-rest-auth.

django-graph-auth's People

Contributors

anthonylobko avatar duffn avatar morgante avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

django-graph-auth's Issues

Can you include Django REST framework?

i am using Django REST framework. I stored token to databse but token return null

https://imgur.com/a/s8PdM
`
from django.conf import settings
from graphene import relay, AbstractType, Mutation, Node
from graphql_relay.node.node import from_global_id
import graphene
from graphene_django.filter import DjangoFilterConnectionField
from graphene_django import DjangoObjectType
import django_filters
import logging
from django.db import models
from django.utils.http import urlsafe_base64_decode as uid_decoder
from django.utils.encoding import force_text

from django.conf import settings
from django.db.models.signals import post_save
from django.dispatch import receiver
from rest_framework.authtoken.models import Token
from django.contrib.auth.models import User
from rest_framework import authentication
from rest_framework import exceptions

from rest_framework.settings import api_settings
from musclemesh.kullanici.settings import graph_auth_settings

import django.contrib.auth
# from django.contrib.auth.tokens import default_token_generator as token_generator
# from django.utils.encoding import force_bytes
# from django.utils.http import urlsafe_base64_encode

UserModel = User

class DynamicUsernameMeta(type):
    def __new__(mcs, classname, bases, dictionary):
        dictionary[UserModel.USERNAME_FIELD] = graphene.String(required=True)
        return type.__new__(mcs, classname, bases, dictionary)

class UserNode(DjangoObjectType):
    class Meta:
        model = UserModel
        interfaces = (relay.Node, )
        only_fields = graph_auth_settings.USER_FIELDS
        filter_fields = graph_auth_settings.USER_FIELDS

    token = graphene.String()
    @classmethod
    def get_node(cls, id, context, info):
        user = super(UserNode, cls).get_node(id, context, info)
        if context.user.id and (user.id == context.user.id or context.user.is_staff):
            return user
        else:
            return None

    def resolve_token(self, args, context, info):
        if self.id != context.user.id and not getattr(self, 'is_current_user', False):
            return None

    @receiver(post_save, sender=settings.AUTH_USER_MODEL)
    def create_auth_token(sender, instance=None, created=False, **kwargs):
        if created:
            token = Token.objects.create(user=instance)
        return token
        # jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
        # jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER

        # payload = jwt_payload_handler(self)
        # token = jwt_encode_handler(payload)

        # return token

class RegisterUser(relay.ClientIDMutation):
    class Input(metaclass=DynamicUsernameMeta):
        username = graphene.String(required=True)
        email = graphene.String()
        password = graphene.String()

    ok = graphene.Boolean()
    user = graphene.Field(UserNode)

    @classmethod
    def mutate_and_get_payload(cls, input, context, info):
        model = UserModel
        if graph_auth_settings.ONLY_ADMIN_REGISTRATION and not (context.user.id and context.user.is_staff):
            return RegisterUser(ok=False, user=None)
        if 'clientMutationId' in input:
            input.pop('clientMutationId')
        email = input.pop('email')
        username = input.pop(UserModel.USERNAME_FIELD, email)
        password = input.pop('password') if 'password' in input else model.objects.make_random_password()

        user = model.objects.create_user(username, email, password, **input)
        user.is_current_user = True

        if graph_auth_settings.WELCOME_EMAIL_TEMPLATE is not None and graph_auth_settings.EMAIL_FROM is not None:
            from mail_templated import EmailMessage
            input_data = user.__dict__
            input_data['password'] = password
            message = EmailMessage(graph_auth_settings.WELCOME_EMAIL_TEMPLATE, input_data, graph_auth_settings.EMAIL_FROM, [user.email])
            message.send()

        return RegisterUser(ok=True, user=user)

# =============================================================
class LoginUser(relay.ClientIDMutation):
    class Input(metaclass=DynamicUsernameMeta):
        username = graphene.String(required=True)
        password = graphene.String(required=True)

    ok = graphene.Boolean()
    user = graphene.Field(UserNode)

    @classmethod
    def mutate_and_get_payload(cls, input, context, info):
        model = UserModel

        params = {
            model.USERNAME_FIELD: input.get(model.USERNAME_FIELD, ''),
            'password': input.get('password')
        }

        user = django.contrib.auth.authenticate(**params)

        if user:
            user.is_current_user = True
            return LoginUser(ok=True, user=user)
        else:
            return LoginUser(ok=False, user=None)


class Query(AbstractType):
    user = relay.Node.Field(UserNode)
    users = DjangoFilterConnectionField(UserNode)

    me = graphene.Field(UserNode)
    def resolve_me(self, args, context, info):
        return UserNode.get_node(context.user.id, context, info)

class Mutation(AbstractType):
    register_user = RegisterUser.Field()
    login_user = LoginUser.Field()

`

Exception when i try to use the mutation examples: "mutate_and_get_payload() got an unexpected keyword argument 'email'"

I am trying to use the examples mutations in api.md:
mutation { registerUser(input: { email: "[email protected]", password: "test_password", firstName: "Morgante", lastName: "Pell" }) { ok, user { id, firstName, email, token } } }

and I get this "mutate_and_get_payload() got an unexpected keyword argument 'email'"

my pip list:
Django (1.11.6)
django-filter (1.1.0)
django-graph-auth (0.3.1)
djangorestframework (3.7.1)
djangorestframework-jwt (1.11.0)
graphene (2.0.dev20170802065539)
graphene-django (2.0.dev2017083101)
graphql-core (2.0.dev20170801051721)
graphql-relay (0.4.5)
iso8601 (0.1.12)
pip (9.0.1)
promise (2.1.dev0)
psycopg2 (2.7.3.1)
PyJWT (1.5.3)
pytz (2017.2)
setuptools (28.8.0)
six (1.10.0)
wheel (0.30.0)

Thanks for your work.

keep this project alive...

I like the features this package provides but I hope there is a up-to-date-out-of-the-box-one-stop-all solution to django/graphene authentication, or simple alternatives

Exception when importing graphe_auth.schema : cannot import name 'DjangoFilterConnectionField'

import graph_auth.schema causes exception importing DjangoFilterConnectionField
probably because I am using the latest graphene / graphene-django which may have changed some things about filters...? Here's my relevant environment:

Django==1.11
django-graph-auth==0.3.1
graphene==1.4
graphene-django==1.3
graphql-core==1.1
graphql-relay==0.4.5
python 3.5

Full stack trace:
django_1 | Internal Server Error: /api/
django_1 | Traceback (most recent call last):
django_1 | File "/usr/local/lib/python3.5/site-packages/graphene_django/settings.py", line 74, in import_from_string
django_1 | module = importlib.import_module(module_path)
django_1 | File "/usr/local/lib/python3.5/importlib/init.py", line 126, in import_module
django_1 | return _bootstrap._gcd_import(name[level:], package, level)
django_1 | File "", line 986, in _gcd_import
django_1 | File "", line 969, in _find_and_load
django_1 | File "", line 958, in _find_and_load_unlocked
django_1 | File "", line 673, in _load_unlocked
django_1 | File "", line 673, in exec_module
django_1 | File "", line 222, in _call_with_frames_removed
django_1 | File "/code/backend/schema.py", line 3, in
django_1 | import graph_auth.schema
django_1 | File "/usr/local/lib/python3.5/site-packages/graph_auth/schema.py", line 5, in
django_1 | from graphene_django.filter import DjangoFilterConnectionField
django_1 | ImportError: cannot import name 'DjangoFilterConnectionField'
django_1 |

thanks for your work on this!

Failed to run server

First of all, thanks for your work ๐Ÿ‘
I followed all your instructions though my server was unable to run. Got this:

Unhandled exception in thread started by <function check_errors..wrapper at 0x03E275D0>
Traceback (most recent call last):
File "C:\Users\Abdoul\AppData\Local\Programs\Python\Python35-32\lib\site-packages\django\utils\autoreload.py", line 226, in wrapper
fn(*args, **kwargs)
File "C:\Users\Abdoul\AppData\Local\Programs\Python\Python35-32\lib\site-packages\django\core\management\commands\runserver.py", line 121, in inner_run
self.check(display_num_errors=True)
File "C:\Users\Abdoul\AppData\Local\Programs\Python\Python35-32\lib\site-packages\django\core\management\base.py", line 374, in check
include_deployment_checks=include_deployment_checks,
File "C:\Users\Abdoul\AppData\Local\Programs\Python\Python35-32\lib\site-packages\django\core\management\base.py", line 361, in run_checks
return checks.run_checks(**kwargs)
File "C:\Users\Abdoul\AppData\Local\Programs\Python\Python35-32\lib\site-packages\django\core\checks\registry.py", line 81, in run_checks
new_errors = check(app_configs=app_configs)
File "C:\Users\Abdoul\AppData\Local\Programs\Python\Python35-32\lib\site-packages\django\core\checks\urls.py", line 14, in check_url_config
return check_resolver(resolver)
File "C:\Users\Abdoul\AppData\Local\Programs\Python\Python35-32\lib\site-packages\django\core\checks\urls.py", line 24, in check_resolver
for pattern in resolver.url_patterns:
File "C:\Users\Abdoul\AppData\Local\Programs\Python\Python35-32\lib\site-packages\django\utils\functional.py", line 35, in get
res = instance.dict[self.name] = self.func(instance)
File "C:\Users\Abdoul\AppData\Local\Programs\Python\Python35-32\lib\site-packages\django\urls\resolvers.py", line 313, in url_patterns
patterns = getattr(self.urlconf_module, "urlpatterns", self.urlconf_module)
File "C:\Users\Abdoul\AppData\Local\Programs\Python\Python35-32\lib\site-packages\django\utils\functional.py", line 35, in get
res = instance.dict[self.name] = self.func(instance)
File "C:\Users\Abdoul\AppData\Local\Programs\Python\Python35-32\lib\site-packages\django\urls\resolvers.py", line 306, in urlconf_module
return import_module(self.urlconf_name)
File "C:\Users\USER\test\lib\importlib_init
.py", line 126, in import_module
return _bootstrap._gcd_import(name[level:], package, level)
File "", line 986, in _gcd_import
File "", line 969, in _find_and_load
File "", line 958, in _find_and_load_unlocked
File "", line 673, in _load_unlocked
File "", line 662, in exec_module
File "", line 222, in _call_with_frames_removed
File "C:\Users\USER\git\AjeServer\AjeServer\AjeServer\urls.py", line 4, in
from .schema import schema
File "C:\Users\USER\git\AjeServer\AjeServer\AjeServer\schema.py", line 30, in
schema = graphene.Schema(query=Query)
File "C:\Users\Abdoul\AppData\Local\Programs\Python\Python35-32\lib\site-packages\graphene\types\schema.py", line 39, in init
self.build_typemap()
File "C:\Users\Abdoul\AppData\Local\Programs\Python\Python35-32\lib\site-packages\graphene\types\schema.py", line 97, in build_typemap
self._type_map = TypeMap(initial_types, auto_camelcase=self.auto_camelcase)
File "C:\Users\Abdoul\AppData\Local\Programs\Python\Python35-32\lib\site-packages\graphene\types\typemap.py", line 56, in init
super(TypeMap, self).init(types)
File "C:\Users\Abdoul\AppData\Local\Programs\Python\Python35-32\lib\site-packages\graphql\type\typemap.py", line 16, in init
self.update(reduce(self.reducer, types, OrderedDict()))
File "C:\Users\Abdoul\AppData\Local\Programs\Python\Python35-32\lib\site-packages\graphene\types\typemap.py", line 64, in reducer
return self.graphene_reducer(map, type)
File "C:\Users\Abdoul\AppData\Local\Programs\Python\Python35-32\lib\site-packages\graphene\types\typemap.py", line 76, in graphene_reducer
return self.construct_objecttype(map, type)
File "C:\Users\Abdoul\AppData\Local\Programs\Python\Python35-32\lib\site-packages\graphene\types\typemap.py", line 147, in construct_objecttype
map[type._meta.name]._fields = self.construct_fields_for_type(map, type)
File "C:\Users\Abdoul\AppData\Local\Programs\Python\Python35-32\lib\site-packages\graphene\types\typemap.py", line 208, in construct_fields_for_type
map = self.reducer(map, field.type)
File "C:\Users\Abdoul\AppData\Local\Programs\Python\Python35-32\lib\site-packages\graphene\types\typemap.py", line 64, in reducer
return self.graphene_reducer(map, type)
File "C:\Users\Abdoul\AppData\Local\Programs\Python\Python35-32\lib\site-packages\graphene\types\typemap.py", line 73, in graphene_reducer
assert _type.graphene_type == type
AssertionError

I have django 1.10.4 and install all the required packages(Graphene-Django, django-filter, django-graph-auth

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.