I just want to give a user details in a login response,
currently, I'm getting 'token' and 'refresh' in
http://127.0.0.1:8000/auth/jwt/create/ JWT login API response.
I want to return with login user details
here is the response snapshot of jwt/create/,
JWT Response Image
As djoser uses django-rest-framework-simplejwt inside, you have to call your custom view instead of the TokenObtainPairView to add user's details in api response.
You can achieve this through following steps:
your_app/urls.py
You have to create your own custom url in order to customize JWT Create API's response.Add the below url path above the "djoser.urls" path so that this url gets called instead of djoser's package jwt/create url.
from your_app.views import CustomTokenObtainPairView
urlpatterns = [
...
path('auth/jwt/token/', CustomTokenObtainPairView.as_view(), name='custom_token_obtain_pair'),
]
your_app/views.py
Now add your custom view class and its corresponding serializer class where you can add user attributes for your api response.
from rest_framework_simplejwt.serializers import TokenObtainPairSerializer
from rest_framework_simplejwt.views import TokenObtainPairView
class CustomTokenObtainPairSerializer(TokenObtainPairSerializer):
def validate(self, attrs):
## This data variable will contain refresh and access tokens
data = super().validate(attrs)
## You can add more User model's attributes like username,email etc. in the data dictionary like this.
data['user_name'] = self.user.username
return data
class CustomTokenObtainPairView(TokenObtainPairView):
serializer_class = CustomTokenObtainPairSerializer
Related
I need to test REST API using postman. API is build using Django REST Framework. Only login user can get access to API. I am not able to find how I can send login credentials using postman. Thanks in advance.
class ApiMemberGroupNameList(views.APIView):
permission_classes = (
permissions.IsAuthenticated,
RequiredOrgPermission,
RequiredOrgStaffMemberPermission)
def get(self, request, **kwargs):
pk = kwargs.get('pk')
hash = kwargs.get('hash')
member_obj = get_object_or_404(Member.objects.filter(org__hash=hash, pk=pk))
return Response(GroupListSerializer(member_obj.groups.all(), many=True).data)
You can use Basic Auth in POSTMAN. Refer to this screenshot:
You could change the HTTP Methods, URLs, Data Payload(under Body tab) etc in the POSTMAN console
UPDATE-1
After your comments, I tried to recreated the problem.What I did was:
created a view
from rest_framework.views import APIView
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
class MySampleView(APIView):
permission_classes = (IsAuthenticated,)
def get(self, request):
return Response(data={"status": True})
Added to urls.py
urlpatterns = [
url(r'^mysampleview/$', MySampleView.as_view())
]
And my POSTMAN response are below:
Authorization Screenshot
Header Screenshot
My conclusion
You may enter wrong credentials, or something else. I would suggest you open a new POSTMAN tab and repeat the procedure, also try to login Django admin using the same credential which is already used in POSTMAN.
If you want to use Basic Authentification to test Django REST API, it must be allowed in Django REST Framework settings:
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework.authentication.BasicAuthentication',
...
I am building an API with Django Rest Framework (DRF) and enabled the authentication/registration through social apps.
For authenticating users via their social accounts I use Django rest-framework Social Oauth2 and it works like a charm. To be sure my user is logged in I created a very simple view in the views.py of my app:
def index(request):
return HttpResponse("is_anonymous: %s" % request.user.is_anonymous)
The result in the browser is the following (it means that the user is logged in):
is_anonymous: False
Now as I am building an API with DRF I may need to retrieve some data of the current user (from request.user) in one of my viewsets but in the following code, the result is not what I expected:
class HelloViewSet(viewsets.ModelViewSet):
queryset = Hello.objects.all()
serializer_class = HelloSerializer
# This is just a random ViewSet, what is
# important is the custom view below
#action(detail=False)
def test(self, request):
return Response(request.user.is_anonymous)
Here the result shows that the user not logged in:
True
So the first view shows that request.user.is_anonymous = False and the second shows that request.user.is_anonymous = True. Both views are in the same file views.py in the same app.
What do I miss here? We are not supposed to get the user instance in an API REST?
I suppose this is because your first view is pure Django and it's not using DRF's DEFAULT_AUTHENTICATION_CLASSES. To enable it, you can add #api_view decorator:
from rest_framework.decorators import api_view
from rest_framework.response import Response
#api_view()
def index(request):
return Response("is_anonymous: %s" % request.user.is_anonymous)
Also you should update DEFAULT_AUTHENTICATION_CLASSES to enable OAuth, like this:
REST_FRAMEWORK = {
...
'DEFAULT_AUTHENTICATION_CLASSES': (
...
'oauth2_provider.contrib.rest_framework.OAuth2Authentication',
'rest_framework_social_oauth2.authentication.SocialAuthentication',
),
}
As neverwalkaloner mentioned in the in the comments, the problem was that I didn't pass any access_token in the header via Authorization: Bearer <token>, so of course the server wasn't able to identify the "logged" user that was making the request. Using curl (or Postman) I could add this token for checking purpose and it worked.
I have a question, how can I add more than one LOGIN_REDIRECT_URL in settings or in views for my differents users.
For example, I have: Administrators, Human Resources, Teachers, students... etc
and for each I need redirect to a different url, panel admin for Admin etc.
I need add groups? or not?
Thanks for your help!
django-allauth get the login redirect URL from method get_login_redirect_url defined in account adapter you can define your custom adapter and override this:
my_app/adapter.py
from allauth.account.adapter import DefaultAccountAdapter
class AccountAdapter(DefaultAccountAdapter):
def get_login_redirect_url(self, request):
url = super(AccountAdapter, self).get_login_redirect_url(request)
user = request.user
'''
# pseudocode, change it to actual logic
# check user role and return a different URL
role = get_user_role(user)
if role == 'student':
url = student_login_redirect_url
if role == 'teacher':
url = teacher_login_redirect_url
'''
return url
Now tell allauth to use our custom adapter by defining the ACCOUNT_ADAPTER in settings.py:
ACCOUNT_ADAPTER = 'my_app.adapter.AccountAdapter'
I want to allow the django users to use a key in the api urls for authentication.
I do not have OAUTH set up yet so I guess the key could be a sesion key or a digest key.
I'm having 2 problems.
I've tried sending this request:
http://192.166.166.11:8000/api?task=search&term=115&csrf_token=s69WAIZqlCTur1XZQr72QhCc7fzqaRtM
First of all, I've tried using the csrf_token but it does not work.
It takes me to the login page.
Secondly, I do not know how to retrieve csrf_token of other users (the admin is trying to get their csrf_tokens).
My attempt:
x = User.objects.get(username='someone')
x.get_session_auth_hash()
gives me the user's authentication hash but it is a different value.
Can someone please guide me get these two problems sorted out?
You are creating a token-based authentication. You already mentioned OAUTH as one option, and I strongly recommend using one of the existing implementations like django-oauth-toolkit. However, you can also create your own quick solution to create a token-based authentication.
Disclaimer: This is for demo purposes only. Do not copy it in any existing project. It will make your application vulnerable.
First, we create an additional model handling the authentication tokens:
/auth_tokens/models.py
from django.db import models
from django.conf import settings
import string, random
def random_string(length = 64, chars=string.ascii_uppercase + string.ascii_lowercase + string.digits):
return ''.join(random.choice(chars) for x in range(length))
class AuthToken(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL)
token = models.CharField(max_length=64, default=random_string)
/auth_tokens/middleware.py
from auth_tokens.models import AuthToken
class AuthTokenMiddleware:
def process_request(self, request):
token = request.GET.get('auth', None)
if not token:
return
token = AuthToken.objects.get(token=token)
request.user = token.user
return request
Including the middleware into your settings.MIDDLEWARE_CLASSES should enable you to add ?token=<token> to your URL to login your users.
I ended up using token authentication:
http://www.django-rest-framework.org/api-guide/authentication/
so I'd like to share the workflow.
First, you need to do the set up. In settings.py, modify INSTALLED_APPS and add REST_FRAMEWORK as in documentation.
Then you need to run python manage.py syncdb because it needs to add some tables.
Then, you need to add some urls to urls.py to route the api.
You can create and retrieve tokens using this code:
from rest_framework.authtoken.models import Token
token = Token.objects.create(user=User.objects.get(username='john'))
print token.key
Lastly, you'll have to modify your view which depends on whether you're using a function based or class based view.
Here is a function based view I used:
from rest_framework.authentication import TokenAuthentication
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework.decorators import authentication_classes, permission_classes
from rest_framework.decorators import api_view
#api_view(['GET', 'POST'])
#authentication_classes((TokenAuthentication,))
#permission_classes((IsAuthenticated,))
#login_required
def mybooks(request):
entries = Book.objects.all()
return render(request, 'mybooks.html', {'entries': entries})
Lastly, to test it out:
import requests
token = '243124c52f7583e320d043c4395bd99f63344035'
headers = {'Authorization' : 'Token {}'.format(token)}
page = requests.post('http://127.0.0.1:8000/mybooks/', headers=headers)
print page.content
Note that in my case I do not need define plain serialization since I have an advanced custom serialization and that is not the topic here.
Django doesn't provide API Keys out of the box.
Use API providers such as Tastypie to have this feature
I made an endpoint called /cars.
A person can create cars with a frontend, but devices read cars using an SDK, which has an API Key. This way, 2 rent-a-car companies can use the API without getting the cars mixed-up. Each app has its own API Key and its own person managing the contents.
This is being implemented with django restframework 3.x and django-oauth-toolkit.
I'm writing a test for a human retrieving cars, and another for a device.
This is failing:
def test_get_list(self):
# devices have a django user (AUTH_USER_MODEL ---onetoone--- Device)
self.client.force_authenticate(user=self.user_device)
self._get_list()
self.client.force_authenticate(user=None)
force_authentication sets request.auth to None. However, with postman or httpie, request.auth contains the Application object.
The queryset is:
def get_queryset(self):
if hasattr(self.request.user, 'device'):
# get the cars created by the owner of the API Key
return self.request.auth.application.user.cars.all()
return self.request.user.cars.all() # get my cars
Does this approach in the queryset make sense?
Am I testing it in the wrong way?
Why is request.auth empty? Is force_authentication using BasicAuthentication?
I would recommend going with check_object_permission for this kind of checks. You can read more here.
DRF documentation states that you need to force_authenticate the request if you are using APIRequestFactory. From the documentation:
from rest_framework.test import force_authenticate
factory = APIRequestFactory()
user = User.objects.get(username='olivia')
view = AccountDetail.as_view()
# Make an authenticated request to the view...
request = factory.get('/accounts/django-superstars/')
force_authenticate(request, user=user)
response = view(request)
To authenticate with APIClient try using credentials. Example from the documentation:
from rest_framework.authtoken.models import Token
from rest_framework.test import APIClient
# Include an appropriate `Authorization:` header on all requests.
token = Token.objects.get(user__username='lauren')
client = APIClient()
client.credentials(HTTP_AUTHORIZATION='Token ' + token.key)
The same is the second question.
As pointed in the documentation force_authenticate bypass authentication therefore it's your job to simulate the missing authentication part, including filling the request.auth.
Otherwise, you'll need to configure a data set and call either login or credential on the APIClient instance.