I've used create-react-app combined with Django Rest Framework to make a small site. Everything works perfectly when I use npm start and hit the Django API from one port to another. When I npm build the static react files and serve them from within the Django app, however, I get 403 forbidden when hitting a number of endpoints. I think it has something to do with CSRF, but I can't figure out what.
I serve the static files from views.py:
#api_view(['GET'])
def serve_html(request):
try:
with open(os.path.join(REACT_APP_DIR, 'build', 'index.html')) as f:
return HttpResponse(f.read())
except FileNotFoundError:
return HttpResponse(
"""
This URL is only used when you have built the production
version of the app. Visit http://localhost:3000/ instead, or
run `yarn run build` to test the production version.
""",
status=501,
)
My urls.py contains the catchall for the static files at the bottom:
urlpatterns = [
# ..all api paths
url(r'^', serve_html, name='serve_html'),
]
I use TokenAuthentication and SessionAuthentication:
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework.authentication.TokenAuthentication',
'rest_framework.authentication.SessionAuthentication',
)
}
And the api requests that require users to be logged in have the following decorators:
#authentication_classes((SessionAuthentication, TokenAuthentication))
#permission_classes((IsAuthenticated,))
Addendum: I notice that when running it cross-origin, there is no sessionid cookie (and things work), but when I try to host react files on same-origin, there is a sessionid cookie (and 403 Forbidden is returned).
Sorry for the open-endedquestion, but I'm at my wit's end here; I really don't know why it's not working.
You do not require the SessionAuthentication class since you are using a token-based HTTP Authentication scheme. This should do the trick:
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework.authentication.TokenAuthentication',
)
}
Hope this helps.
Related
I am using social-app-django GoogleOAuth2 backend and hit a problem with redirect_uri
I managed to setup INSTALLED_APP, AUTHENTICATION_BACKENDS, url.py and add below 3 in settings
SOCIAL_AUTH_GOOGLE_OAUTH2_KEY='MY KEY'
SOCIAL_AUTH_GOOGLE_OAUTH2_SECRET='MY SECRET'
LOGIN_REDIRECT_URL='http://localhost:8000/api/auth/complete/google-oauth2/'
I have http://localhost:8000/api/complete/google-oauth2/ added into my google Authorised redirect URIs.
I triggered auth login by accessing http://127.0.0.1:8000/login/google-oauth2/ (yes, my project use react on frontend, so not using Django templates).
Problem is I always get this error
Error: redirect_uri_mismatch
The redirect URI in the request, http://127.0.0.1:8000/complete/google-oauth2/, does not match the ones authorized for the OAuth client. To update the authorized redirect URIs, visit: ....
The redirect_url in generated auth url is always http://127.0.0.1:8000/complete/google-oauth2/ and if I replace it with the on I configured in Google console, then it works. So I am guessing it must be something settings related.
It looks like redirect url settings does work, any idea what's wrong? Please help!
You can add redirect_uri inside the auth_params along with access_type in settings file.
SOCIALACCOUNT_PROVIDERS = {
'google': {
'SCOPE': [
'profile',
'email',
],
'AUTH_PARAMS': {
'access_type': 'online',
'redirect_uri': 'http://127.0.0.1:8000/<custom-url>'
}
}
}
I have project in django 1.0.4 - yes I know it is old.
I want to use the lack of access to media (audio) files for users who are not logged in.
After making changes to nginx, logged in users also have no access.
I tried with view and url function - no result
my nginx settings:
location /media/content/audio/ {
deny all;
}
my function and url
#login_required
def protected_serve(request, path, document_root=None, show_indexes=False):
if not request.user.is_authenticated:
raise Http404()
else:
return serve(request, path, document_root, show_indexes)
urlpatterns += patterns('',
(r'^media/content/audio/(?P<path>.*)$', protected_serve),
)
You're very close to having the whole puzzle put together. There are two things you need to do:
Configure NGINX that you do want to be able to serve data from a particular folder, but that said folder isn't public. The authorization to send files from a folder will come from the application behind NGINX, not from external requests to NGINX.
Have your django app send the kind of response to NGINX that NGINX understands to mean "serve this file from the protected area in 1"
The way you achieve the first goal is to use the config directive "internal"
Achieving the second goal is to use the HTTP response header "X-Accel-Redirect" as #ralf states in the comments above.
Here is a blog post on the subject: https://clubhouse.io/developer-how-to/how-to-use-internal-redirects-in-nginx/
A Python project to help you achieve the same goal: https://pypi.org/project/django-transfer/
NGINX Docs: https://www.nginx.com/resources/wiki/start/topics/examples/xsendfile/
I am implementing onesingal push notification on my website by reading there documentation OneSignal WebPush notification. There they say that put the corresponding javascript on the top level domain ?
In django all files are located through the route so how i should put a js on the top domain level?
eg
https://yoursite.com/manifest.json
https://yoursite.com/OneSignalSDKWorker.js
Django does not recommend serving static files through a view. So you should use nginx or apache to do it for you. It's quite easy to setup both for serving such files.
Nginx example (not tested) -
location (OneSignalSDKWorker.js|manifest.json) {
root /path/to/files/directory;
}
If you have to do it in Django, you could add the following to your main urls.py -
from django.views.generic import TemplateView
urlpatterns = [
...
path(
"manifest.json",
TemplateView.as_view(
template_name="path/to/manifest.json",
content_type="application/json"
),
name="manifest.json",
),
path(
"OneSignalSDKWorker.js",
TemplateView.as_view(
template_name="path/to/OneSignalSDKWorker.js",
content_type="application/javascript"
),
name="OneSignalSDKWorker.js",
),
...
]
So the docs says that
Upload the files to the top-level root of your site directory. The following URLs should be publicly accessible:
If you running your server in debug mode you can add route to your public static folder(it's better to have two separate folders: for basic static, and for static such as that scripts and 500.html/404.html files). w
So you need to have two separate urlpatterns.
And in production serving static should be stored though http server(such as Nginx)
Got a weird scenario. I am on the Django Rest browser api with a logged in user.
When I update it is okay. But when I try to create a user, this error shows:
CSRF Failed: CSRF token missing or incorrect.
it also auto logged out me every single time.
In views.py, I already have added
permission_classes = (permissions.IsAuthenticatedOrReadOnly,)
Still same error and scenario.
In my settings.py:
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework.authentication.SessionAuthentication',
),
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.AllowAny',
],
}
Anyone experienced this?
I attempting to use the Django OAuth Toolkit in a project I'm working on. I've set up two servers - one as the OAuth provider and another as a client service that is accessed only by authenticated users.
The OAuth provider seems to be working just fine. I'm able to create a link on the client service that directs to the OAuth provider. The user then logs in, and is prompted whether to allow/deny the application. If the user allows the application, the user is then redirected back to the client service, and the URI contains the access token. Because this service needs to be accessible from both a website and a mobile client, I'm using an implicit grant, and following this way of doing things: https://aaronparecki.com/articles/2012/07/29/1/oauth2-simplified#browser-based-apps.
Everything with the provider seems to work as expected, but I'm having issues with the client service app, which is also a Django application. It doesn't appear to recognize the token in the redirect URI, and as a result I'm unable to make any authenticated requests against the service.
I've made the following changes to the client service's settings.py:
I've added the AUTHENTICATION_BACKENDS section, as follows:
AUTHENTICATION_BACKENDS = (
'django.contrib.auth.backends.ModelBackend',
'oauth2_provider.backends.OAuth2Backend',
)
I've added oauth2_provider.middleware.OAuth2TokenMiddleware to the MIDDLEWARE_CLASSES section.
I've added oauth2_provider to the INSTALLED_APPS.
The REST_FRAMEWORK section now looks like:
REST_FRAMEWORK = {
'DEFAULT_MODEL_SERIALIZER_CLASS':
'rest_framework.serializers.HyperlinkedModelSerializer',
'DEFAULT_AUTHENTICATION_CLASSES': (
'oauth2_provider.ext.rest_framework.OAuth2Authentication',
),
'DEFAULT_PERMISSION_CLASSES': (
'rest_framework.permissions.IsAuthenticated',
),
}
I've also added the OAUTH_PROVIDER section:
OAUTH2_PROVIDER = {
# this is the list of available scopes
'SCOPES': {'read': 'Read scope', 'write': 'Write scope', 'groups': 'Access to your groups'}
}
As near as I can figure, there must be something else that I'm missing in my settings.py that will tell Django to look for the token, but I'm at a bit of a loss on what this might be.
Can someone point me in the right direction on what I might be missing here?
EDIT: I should clarify the results I'm getting when attempting to call something on the client service. When I make a curl request to the client service, like so (except with real values plugged in):
curl -H "Authorization: Bearer token_goes_here" https://service.com/api/some_api/call
I get a result of:
{"detail": "Authentication credentials were not provided."}
It's as if the client service isn't looking in the right place for the credentials, which makes me think that something isn't set up quite right.
DEFAULT_PERMISSION_CLASSES IsAuthenticated for REST_FRAMEWORK is blocked non auth requests.
If you planned using javascript to access your REST API see https://github.com/evonove/django-oauth-toolkit/blob/master/oauth2_provider/tests/test_implicit.py
For "Implicit Grant Flow" you must:
login via ModelBackend with user login and password.
create oauth2 application ( /o/applications/ )
or from django console, see test.
get auth token from "/o/authorize/" url with logged in user.
then you must add token to "'HTTP_AUTHORIZATION': 'Bearer ' + access_token," header, to access API resourses.
And, i think, at this workflow we do not need auth_backends and middleware because we have DEFAULT_AUTHENTICATION_CLASSES in REST_FRAMEWORK.
All grant types you can see in DOT based on lib
https://oauthlib.readthedocs.org/en/latest/oauth2/grants/grants.html
Or you can use more simplest "Resource owner password-based" as in DOT documentation described...