I'm having a little trouble with Token Authentication in the Django REST Framework. From the docs I know it is a matter of implementing the following:
from rest_framework.authtoken.models import Token
token = Token.objects.create(user=...)
print token.key
Now my question is, what exactly goes in the argument of Token.objects.create(user=...). The answer here helps and it says That will provide a Token model which is foreign-keyed to User. I'm not sure I understand this.
I have my own model of Users defined like so:
class Users(models.Model):
userid = models.IntegerField(primary_key=True)
username = models.CharField(max_length=255L, unique=True, blank=True)
email = models.CharField(max_length=255L, unique=True, blank=True)
password = models.CharField(max_length=64L, blank=True)
registeredip = models.CharField(max_length=255L, blank=True)
dob = models.DateField(null=True, blank=True)
firstname = models.CharField(max_length=255L, blank=True)
lastname = models.CharField(max_length=255L, blank=True)
joindate = models.DateTimeField()
class Meta:
db_table = 'Users'
How would I create a token for users that satisfy certain conditions in this case?
# View Pseudocode
from rest_framework.authtoken.models import Token
def token_request(request):
if user_requested_token() and token_request_is_warranted():
new_token = Token.objects.create(user=request.user) #What goes here?
Any help or leads to any more documentation/examples would really help me out here. Thank you!
to be sure: we are talking about Token authentication that is provided by django rest framework?
If so, this is very simple method, where there is a token (random 40 characters) that is used instead of username and password.
What is DRF delivering is a table (Token) where you need to create entries for your users, Token is referencing your user model (builtin or active custom model).
There are no tokens created initially, you need to create them.
There are several ways to create tokens, most common are:
create token for all users using signal handler (on create)
create tokens in background task (e.g. management tasks, runining from time to time and creates missing tokens)
have a special api endpoint, that will create token on-demand, with other user authentication method to authorize user
Basically that mean, that somewhere in your code you need to create Token instance, referencing your user instance.
Token(user=user).save()
Now, few remarks:
this implementation of tokens is rather rudimentary, e.g. you do not have any options to expire token, the only way is to regenerate token - this may be problematic if you want expiring sessions and/or multiple clients (remember - one token per user, not browser/session/device)
tokens are created using poor random function
tokens are stored in the database as plain text
there are multiple packages that deliver better and more secure token implementations, the most advanced are django-rest-framework-jwt and django-rest-knox (second one is simpler)
p.s.
python class names should be singular (Users->User)
Related
I would like to ask how I can do authentication and query tags limited to a specific user (owner) using Graphen Relay and Django JWT.
Here is my Model:
class Tag(models.Model):
"""Tag to be used for a objective"""
name = models.CharField(max_length=255)
user = models.ForeignKey(
settings.AUTH_USER_MODEL,
related_name='tag',
on_delete=models.CASCADE,
)
Here is my Schema code:
class TagNode(DjangoObjectType):
class Meta:
model = Tag
filter_fields = ['name']
interfaces = (relay.Node,)
Here is my Query:
class Query(graphene.ObjectType):
tag = relay.Node.Field(TagNode)
all_tags = DjangoFilterConnectionField(TagNode)
def resolve_all_tags(self, info):
# context will reference to the Django request
print(info.context.user)
if not info.context.user.is_authenticated:
return Tag.objects.none()
else:
return Tag.objects.filter(user=info.context.user)
Here is the document for Django JWT: https://github.com/flavors/django-graphql-jwt but I do not know how to get the user (already use info.context.user) but it does not work,
when I tried to add Authorization (JWT token) in the header or as an argument. It also does not work.
Basically you are doing everything correctly and your user should be fetched successfully.
I've just checked and it works in my case, I use JWT like a cookie but it doesn't matter.
Had you authorized your user when tried to get tags?
Because regarding JWT you need to authorize your user and receive the JWT token. Only after that the real user will be presented in the request when you call the tags query. Otherwise the user will be anonymous.
here is my user model.
class User (models.Model):
username = models.CharField(max_length=50)
# token = models.CharField(max_length=50)
email_id = models.EmailField(max_length=50)
password = models.CharField(max_length=50)
is_deleted = models.BooleanField(default=False)
created_at = models.DateTimeField(auto_now_add=True, blank=True)
updated_at = models.DateTimeField(auto_now_add=True, blank=True)
and here is my views for creating user
class UserView(APIView):
def post(self,request):
try:
# RequestOverwrite().overWrite(request, {'token':'string'})
user_data = UserDetailSerializer(data=request.data)
if not(user_data.is_valid()):
return Response(user_data.errors)
user_data.save()
return Response("user created successfully",status=status.HTTP_201_CREATED)
except Exception as err:
print(err)
return Response("Error while creating user")
now what i want to do is to create a token when i post a user and that token is used later for login.
also i want to validate user if it exist in database then make user authenticate.
what should i do..?any suggestion
below is my serializers.py
class UserDetailSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ('id','username','email_id','password','is_deleted','created_at','updated_at')
extra_kwargs = {
'password': {
'required':True,
'error_messages':{
'required':"Please fill this field",
}
}
}
First and foremost, it seems you are defining a custom user that is not in any way connected the Django auth user. It is a very very bad idea and will be difficult to get it work with most Django features. You can check out how to customize the existing user if you really need to.
As for user authentication, using the DRF Token Authentication, the flow is this way:
Client sends request to create user
If user is created successfully, it requests for an authentication token using the user's login and password
The backend verifies user's credentials and issues a token
Client makes subsequent requests with the token
If token expires or user logs out, repeat 2-4
Check out how to do these in DRF's TokenAuthentication documentation.
Your question is not very specific so I'm not sure what sort answer you are expecting but following these steps should get you going.
Token creation should be realized in model User. You can set default value to token field.
Add parameter default to User model token field:
token = models.CharField(default=tokenGenerator, max_length=50)
tokenGenerator should be some function that returns some generated token.
Secondly UserDetailSerializer should be edited to get token if it's necessary but not required.
class UserDetailSerializer(serializers.ModelSerializer):
# You can also provide this default function like in model field
# for this token field
# default=tokenGenerator
token = serializers.CharField(max_length=50, required=False)
class Meta:
model = User
fields = (..., 'token')
extra_kwargs = ...
Now your model gets generated token for newly created User.
User should be auto logged in after registration but it's not that simple.
You need to specify how do you want to communicate with API. You want token so i guess that front should request api and token should be used from cookies.
If you send request from browser eg. jQuery you need to get response with generated token and save it in cookies. Your post response in DRF:
return Response({'token': user_data.get('token')},status=status.HTTP_201_CREATED)
And now you have some more steps:
Attach token to every browser request which requests API
Create authentication class to validate every request checks for correct token
...
Now, if you read this you realize that it needs some work. If you know that and you intentionally want to create this, you need to create mentioned view authentication class.
Else try to use libs like oauth for django. That will provide you ready classes for token management.
Also as #Ken4scholars mentioned, try to use Django User model. It have good methods for validation etc. without make this done manually.
I have a simple ForeignKey relationship between two models:
class Ticket(models.Model):
description = models.CharField(max_length=1000)
created_by = models.ForeignKey(User, related_name="created_ticket")
class User(models.Model):
username = models.CharField(max_length=64, unique=True, primary_key=True)
email = models.CharField(max_length=255)
I have a serialiser for each, with the user serialized within the ticket as a nested serialiser. What I would ideally like is
in an update view of Tickets on the Browsable API, being able to choose from a dropdown list of extant users, and
when entering a username and an e-mail, the application should check if users exist with those parameters, and if so, assign them to the ticket, and if not, raise a validation error (the validation part I got working, the rest... not so much).
So far, I've tried to follow overriding the update/create methods, but when I enter a code, the application always tries to create a new object, then complains that an object with the same username (the pkey) already exists. I have tried getting some sense out of the documentation on the subject, but with not much luck.
EDIT: My update method is
def update(self, instance, validated_data):
usr_data = validated_data.pop('created_by')
instance.created_by_id = usr_data.id
return instance
Question / Problem:
I am building a Django app, with 2 models: User and Secret. Secrets can be made by Users, and other Users can "like" them. I've setup my likes field as a ManyToManyField, so that Users whom like a Secret can be stored there and later retrieved, etc. However, when I try to query for a User and a Secret and use my_secret.likes.add(my_User) nothing happens. I don't receive an error and when I print my Secret's many-to-many likes field, after the add, I see: secrets.User.None.
Why is my add() method running but I am not receiving any errors, and why is my User not properly being added to my Secret's likes?
Note: I've saved both the User and Secret objects upon initial creation. Outside this application I've been able to use the add() method just fine, but in those scenarios I was creating objects in the moment, and not retreiving already existing objects.
Is there a different way to handle add() when using data retreived from a Query? That's my only other line of reasoning right now, and I've followed the documentation here exactly: Django Many-to-Many Docs
I also apologize if this was answered elsewhere on the site. I did find one other post here, but there was no solution provided, granted they were experiencing the exact same issue.
My Models:
class User(models.Model):
"""
Creates instances of a `User`.
Parameters:
-`models.Model` - Django's `models.Model` method allows us to create new models.
"""
first_name = models.CharField(max_length=50) # CharField is field type for characters
last_name = models.CharField(max_length=50)
email = models.CharField(max_length=50)
password = models.CharField(max_length=22)
created_at = models.DateTimeField(auto_now_add=True) # DateTimeField is field type for date and time
updated_at = models.DateTimeField(auto_now=True) # note the `auto_now=True` parameter
objects = UserManager() # Attaches `UserManager` methods to our `User.objects` object.
class Secret(models.Model):
"""
Creates instances of a `Secret`.
Parameters:
-`models.Model` - Django's `models.Model` method allows us to create new models.
"""
description = models.CharField(max_length=100) # CharField is field type for characters
user = models.ForeignKey(User, related_name="secrets") # One-to-Many Relationship
likes = models.ManyToManyField(User) # Many to Many Relationship
created_at = models.DateTimeField(auto_now_add=True) # DateTimeField is field type for date and time
updated_at = models.DateTimeField(auto_now=True) # note the `auto_now=True` parameter
objects = SecretManager() # Attaches `SecretManager` methods to our `Secret.objects` object.
Problem Example:
The model migrates fine, everything seems to be in proper syntax. However, when I try and retrieve a User and a Secret, and add the User to the Secret.likes, the add() method gives no errors, runs, but no objects are saved.
Here's an example:
tim = User.objects.get(email="tim#tim.com") # Gets a user object
my_secret = Secret.objects.get(id=2) # Gets a secret object
# This is where nothing seems to happen / take:
my_secret.likes.add(tim) # add() method per Django many-to-many docs
print my_secret.likes # returns: `secrets.User.None` -- why?
Why when printing my_secret.likes above, is nothing printed?
Especially when:
tim.secret_set.all() shows the secret containing an id=2 as in the above example....so the User is recording the relationship with the Secret, but the Secret is not recording any relationship with the User. What am I doing wrong?
You need to call the all method of the many-to-many field to view all related objects:
print my_secret.likes.all()
# ^^^^^
I know that superusers and regular users are both just django's User objects, but how can I write a custom user class that requires some fields for plain users and doesn't require those fields for superusers?
No structure in the database is tricky. JSONFields for example may prove to be extremely hard to tame when the app grows.
I would go and try to make it "simple" - more maintainable (I imagine if you need to do stuff like that you may want to extend the model in the future). If this is a new project you can easily change the default user model. But that may or may not help you with your case.
You can always make two models:
from django.db import models
from django.contrib.auth.models import AbstractBaseUser
class Mortal(AbstractBaseUser):
is_superuser = False
username = models.CharField(max_length=256)
first_name = models.CharField(max_length=256)
last_name = models.CharField(max_length=256)
class Admin(AbstractBaseUser):
is_superuser = True
username = models.CharField(max_length=256)
and then make your own authentication backend:
class MyBackend(object):
"""
Danger! A backend to authenticate only via username
"""
def authenticate(self, username=None):
try:
return Mortal.objects.get(username=username)
except Mortal.DoesNotExist:
try:
return Admin.objects.get(username=username)
except Admin.DoesNotExist:
return None
You can have a profile class (say UserProfile) with foreign key to the user that is to be created only when user signs up using the website's registration form. That way, superuser which is created on admin site or through command line wouldn't need an extra profile instance attached to it.