So I have a Django app with Swagger, but I also added a custom authenticator to every endpoint automatically with
settings.py
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'cheers.utils.authenticator.CognitoAuthentication',
),
}
urls.py
schema_view = get_schema_view(
openapi.Info(
title="Resource API",
default_version="v1",
description="A sample API for resource with DRF",
terms_of_service="https://www.google.com/policies/terms/",
contact=openapi.Contact(email="cheersocialinc#gmail.com"),
license=openapi.License(name="BSD License"),
),
public=True,
permission_classes=(
permissions.AllowAny,), # Anyone have access to API documentation
)
if settings.DEBUG:
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
urlpatterns += ADMIN_URLS
urlpatterns += SWAGGER_URLS
How do I turn this off for swagger and admin url? The reason I'm not sure is because Swagger and admin is added to URLs it's not a view
urls.py
How do I disable automatic authentication for swagger?
Also I guess a side question would be how to disable this URL when debug is False
To disable authentication | permission on swagger urls, set permission_classes in get_schema_view like this :
urls.py
from django.urls import path
from rest_framework import permissions
from rest_framework.schemas import get_schema_view
from django.conf import settings
schema_view = get_schema_view(
openapi.Info(
title="Resource API",
default_version="v1",
description="A sample API for resource with DRF",
terms_of_service="https://www.google.com/policies/terms/",
contact=openapi.Contact(email="your_email#yopmail.com"),
license=openapi.License(name="BSD License"),
),
public=True,
permission_classes=(
permissions.AllowAny, ), # Anyone have access to API documentation
)
if settings.DEBUG == False
# urlpatterns
urlpatterns = [
# Production urls only
]
else:
urlpatterns = [
# Production urls + swagger doc urls
path(
'doc/',
schema_view.with_ui('swagger', cache_timeout=0),
name='schema-swagger-ui'),
]
For Django admin without authentication follow this post.
Related
I have installed rest_framework_swagger successfully, after that I set url in urls.py file project:
from django.contrib import admin
from django.urls import path, include, re_path
from unimiproject.router import router
from rest_framework.authtoken import views
from rest_framework.schemas import get_schema_view
from django.views.generic import TemplateView
urlpatterns = [
path('admin/', admin.site.urls),
path('api-auth/', include('rest_framework.urls')),
re_path(r"^appjud/",include("appjud.urls")),
path('api/', include(router.urls)),
path('api-token-auth/', views.obtain_auth_token, name='api-token-auth'),
path('openapi/', get_schema_view(
title="School Service",
description="API developers hpoing to use our service"
), name='openapi-schema'),
path('docs/', TemplateView.as_view(
template_name='documentation.html',
extra_context={'schema_url':'openapi-schema'}
), name='swagger-ui')
]
but if I browse http://172.18.0.1:7000/openapi/ I get this:
Schema
GET /openapi/
HTTP 401 Unauthorized
Allow: GET, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept
WWW-Authenticate: Token
{
"detail": "Authentication credentials were not provided."
}
Why do I get "Authentication credentials were not provided"? It should show me schema of all apis not to test they.
Try using permission_classes=(permissions.AllowAny,) to your code
then the user not needed a username and password to assess your documentation
from rest_framework import permissions
from drf_yasg import openapi
path('openapi/',get_schema_view(
openapi.Info(
title="School Service",
description="API developers hoping to use our service",
contact=openapi.Contact(email="mail#domain.com"),
license=openapi.License(name="Proprietary Software"),
),
public=True,
permission_classes=(permissions.AllowAny,),
))
I am working with Django Rest swagger. But it's not showing up all the APIs.
The url paths for /tickets are missing:
Even path to /dj-rest-auth/user/ is missing as well:
Backend/urls.py
from django.contrib import admin
from django.urls import path, include
from rest_framework_swagger.views import get_swagger_view
schema_view = get_swagger_view(title='API')
urlpatterns = [
path('admin/', admin.site.urls),
#path('api/v1/', include(api_urlpatterns)),
#path('dj-rest-auth/', include('dj_rest_auth.urls')),
path('dj-rest-auth/', include('dj_rest_auth.urls')),
path('dj-rest-auth/registration/', include('dj_rest_auth.registration.urls')),
path('api/', include('ticket.urls')),
path('swagger/', schema_view)
]
Tickets/urls.py
from django.urls import path
from ticket import views
urlpatterns = [
path('tickets/', views.ticket_list),
path('tickets/<int:pk>/', views.ticket_detail),
]
My directory structure:
Try with below code:
REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES': (
'rest_framework.permissions.AllowAny',
),
.......
.......
}
I solved this by going in settings.py file and set DEBUG=True.
In my application I need to have multiple Swagger pages with grouped endpoints for multiple clients.
One of my clients (paths) supplies mobile app API, another supplies web client API. URL patterns are kept in 2 different urls.py accordingly.
I'm using drf-yasg to generate schema for my API.
To generate swagger specification for those I'm initializing 2 separate schema_views for each urls.py file like this:
from api_mobile.urls import urlpatterns as mobile_patterns
from api_web.urls import urlpatterns as web_patterns
mobile_schema_view = get_schema_view(
openapi.Info(
title="Mobile API",
default_version='v3',
),
public=True,
permission_classes=(permissions.AllowAny,),
patterns=mobile_patterns,
)
web_schema_view = get_schema_view(
openapi.Info(
title="Web API",
default_version='v1',
),
public=True,
permission_classes=(permissions.AllowAny,),
patterns=web_patterns,
)
urlpatterns = [
path(
'api/mobile/docs',
mobile_schema_view.with_ui('swagger', cache_timeout=0),
name='mobile-schema-ui'
),
path(
'api/web/docs',
web_schema_view.with_ui('swagger', cache_timeout=0),
name='web-schema-ui'
),
path('api/mobile/v3/', include('api_mobile.urls'), name='mobile_urls'),
path('api/web/v1/', include('api_web.urls'), name='web_urls'),
...
]
Where mobile_patterns and web_patterns are just a list of url patterns.
If I open http://localhost:8000/api/mobile/docs or http://localhost:8000/api/web/docs I do see correctly generated schema for both lists of patterns, yet if I try to do a request directly from swagger specification page all endpoints return 404 error – they all try to do a request to non-existing url pattern without providing full path to endpoint.
So if I do a request to any view from mobile endpoints swagger tries to do a request at
http://localhost:8000/some_mobile_url/ instead of http://localhost:8000/api/mobile/v3/some_mobile_url/
And situation is the same for another schema, swagger wrongly requests http://localhost:8000/some_web_url/ instead of using full path
http://localhost:8000/api/web/v3/some_web_url/
Obviously being able to test API directly through swagger is very important so specification itself is not enough in my case.
Is this an issue in me misconfiguring swagger itlesf or should I be somehow providing path to swagger so it prepends full path to each url accordingly?
This is working fine for us:
api_schema.py
from django.conf.urls import include, url
from drf_yasg.views import get_schema_view
from drf_yasg import openapi
from books.api.v1.urls import urlpatterns as api_v1
API_DESCRIPTION = openapi.Info(
...
)
schema_view = get_schema_view(
info=...,
...
url='https://oursite.company.io/',
patterns=[
url('api/v1/', include(api_v1)),
],
)
books.api.v1.urls.py
from django.conf.urls import include, url
urlpatterns = [
url(r'^books', ...),
...
]
urls.py
from ...api_schema import schema_view
...
url(r'^api/v1/', include(api_v1)),
url(r'^api/schema(?P<format>\.json|\.yaml)$',
schema_view.without_ui(cache_timeout=0),
name='api_schema_v1'),
...
I am having trouble implementing token authentication with JWT in the Django rest framework with a Typscript frontend. I'm getting
{detail: "Authentication credentials were not provided."}
with my API call via Typescript, which is:
readonly BASE_URL = 'http://127.0.0.1:8000/'
api_url = this.BASE_URL + 'items/'
auth_url = this.BASE_URL + "api-token-auth/"
getItemsService(token) {
const headers = new HttpHeaders()
headers.append('Content-Type', 'application/json')
headers.append('Authorization', 'JWT ' + token.token)
return this.http.get(this.api_url, {headers: headers})
}
Logging in works fine. It's when I try to load the items that I have issues.
Here's my Django code:
views.py
from rest_framework import generics
from .models import Item
from .serializers import ItemSerializer
class ItemList(generics.ListCreateAPIView):
queryset = Item.objects.all()
serializer_class = ItemSerializer
class ItemDetail(generics.RetrieveUpdateDestroyAPIView):
queryset = Item.objects.all()
serializer_class = ItemSerializer
items/urls.py
from django.urls import path
from .views import ItemList, ItemDetail
urlpatterns = [
path('', ItemList.as_view()),
path('<int:pk>/', ItemDetail.as_view()),
]
project/urls.py
from django.contrib import admin
from django.urls import include, path
from rest_framework_jwt.views import obtain_jwt_token
urlpatterns = [
path('items/', include('groceries.urls')),
path('admin/', admin.site.urls),
path('api-auth/', include('rest_framework.urls')),
path('api-token-auth/', obtain_jwt_token),
]
settings.py
REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES': (
'rest_framework.permissions.IsAuthenticated',
),
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework_jwt.authentication.JSONWebTokenAuthentication',
),
}
I thought the issue would have to be with Django, but I am able to get what I expect with
curl -H "Authorization: JWT <token>" http://localhost:8000/items/
If my backend was not set up correctly, this wouldn't work. So it must be my frontend code.
Based on what you described, It may be a CORS issue. Because you have access to your api endpoint via curl command. But not with browser.
Cross-Origin Resource Sharing (CORS) is a mechanism that uses additional HTTP headers to tell a browser to let a web application running at one origin (domain) have permission to access selected resources from a server at a different origin. A web application makes a cross-origin HTTP request when it requests a resource that has a different origin (domain, protocol, and port) than its own origin.
I checked your Angular typescript code, It seems fine. I suggest to follow below instructions in your django project and see how it goes:
1) install it for pip via pip install django-cors-headers command.
2) In settings.py file, add this app to your installed apps:
INSTALLED_APPS = (
...
'corsheaders',
...
)
3) You will also need to add a middleware class to listen in on responses:
MIDDLEWARE = [ # Or MIDDLEWARE_CLASSES on Django < 1.10
...
'corsheaders.middleware.CorsMiddleware',
'django.middleware.common.CommonMiddleware',
...
]
remember CorsMiddleware should be placed as high as possible.
4) Add this line to your settings.py file.
CORS_ORIGIN_ALLOW_ALL = True
for full documentation refer to django-cors-headers.
I am using django-social-auth for google apps authentication for my django project. I obtained the client id and secret key from Google api console for my domain. And plugged in the values in my app as follows:
**settings.py**
MIDDLEWARE_CLASSES = (
'social_auth.middleware.SocialAuthExceptionMiddleware',
)
LOGIN_URL = '/login/google-oauth2/'
LOGIN_REDIRECT_URL = '/profile'
LOGIN_ERROR_URL = '/login-error/'
AUTHENTICATION_BACKENDS = (
'social_auth.backends.google.GoogleOAuth2Backend',
'django.contrib.auth.backends.ModelBackend',
)
TEMPLATE_CONTEXT_PROCESSORS = (
"django.contrib.auth.context_processors.auth",
"social_auth.context_processors.social_auth_by_type_backends",
)
SOCIAL_AUTH_ENABLED_BACKENDS = ('google',)
SOCIAL_AUTH_DEFAULT_USERNAME = 'new_social_auth_user'
GOOGLE_OAUTH2_CLIENT_ID = '***.apps.googleusercontent.com'
GOOGLE_OAUTH2_CLIENT_SECRET = '****'
GOOGLE_WHITE_LISTED_DOMAINS = ['127.0.0.1:8000']
SOCIAL_AUTH_COMPLETE_URL_NAME = 'socialauth_complete'
SOCIAL_AUTH_ASSOCIATE_URL_NAME = 'socialauth_associate_complete'
SOCIAL_AUTH_RAISE_EXCEPTIONS = False
SOCIAL_AUTH_PROCESS_EXCEPTIONS = 'social_auth.utils.log_exceptions_to_messages'
INSTALLED_APPS = (
'social_auth', )
...
**urls.py**
from django.conf.urls import patterns, include, url
from django.contrib import admin
from django.views.generic import TemplateView
from django.contrib.auth.views import logout
admin.autodiscover()
urlpatterns = patterns('',
url(r'^admin/', include(admin.site.urls)),
url(r'', include('social_auth.urls')),
url(r'^$', TemplateView.as_view(template_name="login.html")),
url(r'^logout/$', logout, {'next_page': '/'}, name='gauth_logout'),
url(r'^profile/$', TemplateView.as_view(template_name="profile.html")),
)
...
**login.html**
<p>Use your work email credentials to sign in to this application:
Sign In
</p>
The problem is that when I click on sign in I am redirected to the Error: Invalid_client page with the details:
Request Details
cookie_policy_enforce=false
scope=https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/userinfo.profile
response_type=code
redirect_uri=http://127.0.0.1:8000/complete/google-oauth2/
state=WZWyJgDRfeW4RneRynqSZ3nSy0Bzs0v6
client_id=None
https://accounts.google.com/o/oauth2/auth?scope=https://www.googleapis.com/auth/userinfo.email+https://www.googleapis.com/auth/userinfo.profile&state=WZWyJgDRfeW4RneRynqSZ3nSy0Bzs0v6&redirect_uri=http://127.0.0.1:8000/complete/google-oauth2/&response_type=code&client_id=None
Even though I have provided the correct client_id in my project, the page (and as can be seen from the url) says that it has not been provided. If I plug it manually in the url, I am redirected to the permissions page though.
Also when I accept the permissions I get an AuthCanceled at /complete/google-oauth2/ error. Is it that my project is not reading the social_auth settings correctly?
Any help would be appreciated. Thanks.
i was having the same problem just change
GOOGLE_OAUTH2_CLIENT_ID = '***.apps.googleusercontent.com'
GOOGLE_OAUTH2_CLIENT_SECRET = '****'
To
SOCIAL_AUTH_GOOGLE_OAUTH2_KEY = '****.apps.googleusercontent.com'
SOCIAL_AUTH_GOOGLE_OAUTH2_SECRET ='****'
in the settings.py file