Authenticate restframework User in python - python

So, i new in django and djangorestframework. i followed their tutorial in their page. http://www.django-rest-framework.org/tutorial/4-authentication-and-permissions/
in that tutorial, you can login as django user from djangorestframework api login page. my question is, if i want to make a CLI or GUI application and using requests module to post a content to the API, but the API must be loggged in first. how i do that?

In DRF, you can add additional package for simple token-based Authentication. Add rest_framework.authtoken to INSTALLED_APPS. To make HTTP(S) request to client you pass the authorization token like this Authorization: Token 9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b
For testing, you can use curl
curl -X GET http://127.0.0.1:8000/api/example/ -H 'Authorization: Token 9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b
Read more...

You can set that a user must be authenticated at all times as default setting in settings.py (in your web server project):
REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES': (
'rest_framework.permissions.IsAuthenticated',
),
More info about that here.
In your web client project, like one of the comments on your questions mentions, you must add an Authentication header in the HTTP messages you send to the web server. An example (TypeScript Angular application implementation) would be:
import {Injectable} from '#angular/core';
import {HttpClient, HttpHeaders} from '#angular/common/http';
import {Observable} from 'rxjs/Observable';
import {Spacecraft} from '../model/spacecraft';
/* Create the authentication headers for the HTTP requests to the DRF project's API.
* Note: uses btoa(): base-64 encoding of ASCII string, see https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/btoa.
*/
const basicAuthenticationToken = btoa(environment.REST_API.username + ':' + environment.REST_API.password);
const httpOptions = {
headers: new HttpHeaders({
'Authorization': `Basic ${basicAuthenticationToken}`
})
};
#Injectable()
export class APICommunicationService {
constructor(private http: HttpClient,
private notificationsService: NotificationsService) {
}
getSpacecraftInfo(url: string): Observable<Spacecraft> {
return this.http.get<Spacecraft>(url, httpOptions)
}
}

Related

Django OAuth Toolkit and Django Rest Swagger Integration

I'm using OAuthToolkit and DjangoRestSwagger. I've created an application using Django Admin, and now I've client_id and client_secret.
I want to generate the token using client_id and client_secret. Currently, I use curl to generate the token.
curl -X POST -d "grant_type=client_credentials" -u"client_id:client_secret" http://localhost:8000/o/token/
How can I do it using the Swagger docs.? Basically, how can integrate third party(OAuthToolkit) API URLs with Swagger?
Currently, I've an Authorize button which takes api_key value, ie the token.
Here's my Swagger settings.
SWAGGER_SETTINGS = {
'SECURITY_DEFINITIONS': {
'token': {
'type': 'apiKey',
'name': 'AUTHORIZATION',
'in': 'header',
}
},
}
Not certain about django-rest-swagger but if you are looking for an alternative with gauranteed support for oauth you can use drf-yasg (yet another swagger generator)
Documentation for yasg adding oauth paths to swagger

How do you post request authenticated in Qt to django rest framework with BasicAuthentication?

I want to send data through a post request but only those who are authenticated can do it. In django application I added the BasicAuthentication in settings.py
...
REST_FRAMEWORK = {
'PAGE_SIZE': 10,
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework.authentication.BasicAuthentication',
)
}
and in Qt post authenticated to do so
...
QNetworkRequest request;
QUrl url("https://.../data/");
url.setUserInfo("username:password");
request.setUrl(url);
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
QString json = QString(...);
QNetworkReply *reply = m_manager->post(request, json.toUtf8());
...
As an error the server returns me -> Error transferring https://username:password#.../data/ - server replied: Bad Request.
I can not understand whether the problem lies in the way in which pass username: password or django app.
Set user info just appends the "username:password" to the URL authority section. See the docs for an example. For HTTP basic authentication, you need to use something similar to this answer.

How do i programmatically logout user?[Django]

I know to logout user in Django. If i want to logout user, i would do
from django.contrib.auth import logout
def logout_view(request):
logout(request)
But what is the relevant way of logging out the user if i am using django oauth toolkit(DOT)?
Should i follow the same or delete the token? Some says delete the token and some says expiry period should be expired. Please provide me the best possible resolution for logging out in DRF using DOT.
You can check Revoking an OAuth2 Token
You’ve granted a user an Access Token, following part 1 and now you would like to revoke that token, probably in response to a client request (to logout).
And Do you logout a user who login via OAuth2 by expiring their Access Token?
EDIT
# OAuth2 provider endpoints
oauth2_endpoint_views = [
url(r'^authorize/$', oauth2_views.AuthorizationView.as_view(), name="authorize"),
url(r'^token/$', oauth2_views.TokenView.as_view(), name="token"),
url(r'^revoke-token/$', oauth2_views.RevokeTokenView.as_view(), name="revoke-token"),
]
If you follow the tutorial part2 you will find you already have the revoke-token url, so you just need to send request to this url.
EDIT2
Let me try to explain this clearly
When you use Django OAuth Toolkit and DRF, you usually will use
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'oauth2_provider.ext.rest_framework.OAuth2Authentication',
)
}
And you can get access token by
curl -X POST -d "grant_type=password&username=<user_name>&password=<password>" -u"<client_id>:<client_secret>" http://localhost:8000/o/token/
And get response like this
{
"access_token": "<your_access_token>",
"token_type": "Bearer",
"expires_in": 36000,
"refresh_token": "<your_refresh_token>",
"scope": "read write groups"
}
Now you can use your access_token to request the api you set like this
curl -H "Authorization: Bearer <your_access_token>" http://localhost:8000/users/1/
How to logout depends on how you define login
Website define login from the session in cookies. When you developing a mobile app, You will define login depend on message in your app (user credentials present in keychain or not when it comes to IOS), and that is what your code do:
from django.contrib.auth import logout
def logout_view(request):
logout(request)
You can see source code here django-logout and docs here
flush()
Deletes the current session data from the session and deletes the session cookie. This is used if you want to ensure that the previous session data can’t be accessed again from the user’s browser (for example, the django.contrib.auth.logout() function calls it).
But remember, From Luke Taylor
The lifetime of the access_token is independent of the login session of a user who grants access to a client. OAuth2 has no concept of a user login or logout, or a session, so the fact that you expect a logout to revoke a token, would seem to indicate that you're misunderstanding how OAuth2 works. You should probably clarify in your question why you want things to work this way and why you need OAuth.
Finally In your case, I think you need to revoeke the token before logout:
def revoke-token(request):
# just make a request here
# POST /o/revoke_token/ HTTP/1.1 Content-Type: application/x-www-form-urlencoded token=XXXX&client_id=XXXX&client_secret=XXXX
def logout(request):
response = revoke-toke(request)
# if succeed
logout(request)

Rest authentication with python social auth and Satellizer

I am trying to enable authentication in my single page angular app using Satellizer as client on frontend and python social auth on backend using django rest framework. The main problem is that I want to use JWT instead of session authentication.
I have tried passing the response I get after the user confirms the popup window to social/complete/backend (python social auth view) but with no luck.
In satellizer for google configuration I put:
$authProvider.google({
clientId:'609163425136-1i7b7jlr4j4hlqtnb1gk3al2kagavcjm.apps.googleusercontent.com',
url: 'social/complete/google-oauth2/',
optionalUrlParams: ['display', 'state'],
state: function() {
return Math.random();
}
});
The problems I encounter are in python social auth:
Missing needed parameter state
for google-oauth2
and
Missing needed parameter code
for facebook.
That is very strange to me because those parameters are present in the request payload and I can get then in my own custom view.
The closest I have come to a solution is writing my own view in which I can accept the parameter state normally.
This is my view which handles the response and creates a new jwt token using the django-rest-framework-jwt:
class SocialAuthView(APIView):
throttle_classes = ()
permission_classes = ()
authentication_classes = ()
social_serializer = SocialAuthSerializer
user_serializer = None
def post(self, request):
access_token_url = 'https://accounts.google.com/o/oauth2/token'
people_api_url = 'https://www.googleapis.com/plus/v1/people/me/openIdConnect'
from django.conf import settings
payload = dict(client_id=request.data['clientId'],
redirect_uri=request.data['redirectUri'],
client_secret=settings.SOCIAL_AUTH_GOOGLE_OAUTH2_SECRET,
code=request.data['code'],
grant_type='authorization_code')
# Step 1. Exchange authorization code for access token.
import requests
import json
r = requests.post(access_token_url, data=payload)
token = json.loads(r.text)
headers = {'Authorization': 'Bearer {0}'.format(token['access_token'])}
# Step 2. Retrieve information about the current user.
r = requests.get(people_api_url, headers=headers)
profile = json.loads(r.text)
try:
user = User.objects.filter(email=profile['email'])[0]
except IndexError:
pass
import jwt
from rest_framework_jwt.utils import jwt_payload_handler, jwt_encode_handler
if user:
payload = jwt_payload_handler(user)
token = jwt_encode_handler(payload)
return Response({'token': token.decode('unicode_escape')},
status=status.HTTP_200_OK)
u = User.objects.create(username=profile['name'], first_name=profile['given_name'],
last_name=profile['family_name'], email=profile['email'])
payload = jwt_payload_handler(user)
token = jwt_encode_handler(payload)
return Response({'Bearer': token.decode('unicode_escape')},
status=status.HTTP_200_OK)
I mean, it works, but I don't get all the benefits that I would get if I could implement it with python social auth. Maybe there is a way to authenticate with python social auth calling some functions like do_auth from this view?
It amazes me how much I struggle with this problem.
All help is welcome.
tl,dr: How to implement angular single page application using Satellizer, django-rest-framework, python social auth and JWT?
Not quite an answer, but I don't have sufficient reputation to comment.
I've been trying to do something similar. Satellizer works well with DRF's djoser module for email/pass token auth.
As for the social aspect, I'm finding OAuth2 quite complicated. You might want to look at the following project (no relation to me), it seems to be trying to implement just that (angularjs-satellizer/psa/jwt):
https://github.com/hsr-ba-fs15-dat/opendatahub
specifically:
https://github.com/hsr-ba-fs15-dat/opendatahub/blob/master/src/main/python/authentication/views.py

How to use TokenAuthentication for API in django-rest-framework

I have a django project, using django-rest-framework to create api.
Want to use token base authentication system so api call for (put, post, delete) will only execute for authorized user.
I installed 'rest_framework.authtoken' and created token for each users.
So, now from django.contrib.auth.backends authenticate, it returns user, with auth_token as attribute. (when loged in successfully).
Now my question is how can I send the token with post request to my api and
at api side how can I verify if token is valid and belongs to the correct user?
Are there any methods in app rest_framework.authtoken to validate given user and its token?
not found this very useful!
Update (changes I made):
Added this in my settings.py:
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework.authentication.BasicAuthentication',
'rest_framework.authentication.SessionAuthentication',
'rest_framework.authentication.TokenAuthentication',
)
}
Also sending Token in my header but its still not working:
if new_form.is_valid:
payload= {"createNewUser":
{ "users": request.POST["newusers"],
"email": request.POST["newemail"]
}
}
headers = {'content-type' : 'application/json',
'Authorization': 'Token 6b929e47f278068fe6ac8235cda09707a3aa7ba1'}
r = requests.post('http://localhost:8000/api/v1.0/user_list',
data=json.dumps(payload),
headers=headers, verify=False)
"how can I send the token with post request to my api"
From the docs...
For clients to authenticate, the token key should be included in the Authorization HTTP header. The key should be prefixed by the string literal "Token", with whitespace separating the two strings. For example:
Authorization: Token 9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b
"at api side how can I verify if token is valid and belongs to the correct user?"
You don't need to do anything, just access request.user to return the authenticated user - REST framework will deal with returning a '401 Unauthorized' response to any incorrect authentication.
To answer the first half of your question:
how can I send the token with post request to my api
You can use the Python requests library. For the django-rest-framework TokenAuthentication, the token needs to be passed in the header and prefixed by the string Token (see here):
import requests
mytoken = "4652400bd6c3df8eaa360d26560ab59c81e0a164"
myurl = "http://localhost:8000/api/user_list"
# A get request (json example):
response = requests.get(myurl, headers={'Authorization': 'Token {}'.format(mytoken)})
data = response.json()
# A post request:
data = { < your post data >}
requests.post(myurl, data=data, headers={'Authorization': 'Token {}'.format(mytoken)})
I finally have the django "rest-auth" package working for token authentication.
If this helps, here is the client-side jQuery code that worked for me, after you successfully log in and receive the "auth_token":
var user_url = {API URL}/rest-auth/login
var auth_headers = {
Authorization: 'Token ' + auth_token
}
var user_ajax_obj = {
url : user_url,
dataType : 'json',
headers: auth_headers,
success : function(data) {
console.log('authorized user returned');
},
error: function(XMLHttpRequest, textStatus, errorThrown) {
console.log('error returned from ' + user_url);
}
};
$.ajax(
user_ajax_obj
);
If you are using coreapi. To add the Authorisation you do
import coreapi
auth = coreapi.auth.TokenAuthentication(scheme='Token', token=token_key)
Then you can do
client = coreapi.Client(auth=auth)
response = client.get(my_url)

Categories

Resources