This article is a very useful article to study the process of linking OAuth2 between two django projects created in the local environment. This is a summary with some notes added for myself, referring to projects-oauth2 /). Except for the changes in the URLconf and django.contrib.auth writing styles that accompany the django version upgrade, the original article is mostly diverted.
Create two Django projects (test_provider, test_consumer) in your local environment and get (dummy) profile information with OAuth2
test_provider --Startup port 8000 --Hold user ID and hashed password --Provide an OAuth2 provider --Ask the user permission to provide information to test_provider -** Use django-oauth-toolkit **
test_consumer --Startup port 8001 --The first web page the user will see --After user authorization, make a request to test_provider and get information -Use ** django-allauth **
test-oauth
│
├── test_consumer
│ ├── templates
| | └──index.html
| |
│ ├── test_consumer
| | ├── __init__.py
| | ├── settings.py
| | ├── urls.py
| | └── wsgi.py
| |
| ├── testprovider
| | ├── __init__.py
| | ├── provider.py
| | ├── urls.py
| | └── wsgi.py
| |
│ ├── manage.py
│ └── db.sqlite3
├── test_provider
| ├── templates
| | └──registration
| | └──login.html
| |
| ├── test_provider
| | ├── __init__.py
| | ├── settings.py
| | ├── urls.py
| | └── wsgi.py
| |
| ├── db.sqlite3
| └── manage.py
|
├── .gitignore
├── Pipfile
└── Pipfile.lock
mkdir test-oauth
$ cd test-oauth
$ pipenv --python 3.8
$ pipenv install django, django-oauth-toolkit, django-cors-headers
$ pipenv shell
(pipenv)$ django-admin.py startproject test_provider
(pipenv)$ cd test_provider
settings.py
INSTALLED_APPS = [
#add to
'oauth2_provider',
'corsheaders',
]
settings.py
MIDDLEWARE = [
#add to
'corsheaders.middleware.CorsMiddleware',
]
As mentioned in the Official Documentation,
It seems that you have to write it on the built-in middleware 'django.middleware.common.CommonMiddleware'
.
settings.py
CORS_ORIGIN_ALLOW_ALL = True
test_provider/urls.py
from django.contrib import admin
from django.urls import path, include
from .views import profile_view, top_view
urlpatterns = [
path('admin/', admin.site.urls),
path('o/', include('oauth2_provider.urls', namespace='oauth2_provider')),
path('', top_view),
path('accounts/', include('django.contrib.auth.urls')),
path('api/profile/', profile_view, name='profile'),
]
Because I want to create it quickly, the login function uses ** django.contrib.auth **, which is a built-in authentication function, and throws URL patterns and views in full (templates need to be created by yourself).
test_provider/views.py
from django.http import JsonResponse
from oauth2_provider.views.generic import ProtectedResourceView
from django.http import HttpResponse
def top_view(request):
return HttpResponse("It works!")
class ProfileView(ProtectedResourceView):
def get(self, request, **kwargs):
user = request.resource_owner
return JsonResponse({
'user_id': user.id,
'email': user.email,
'date_joined': user.date_joined,
'secret_message': 'This is secret message',
})
profile_view = ProfileView.as_view()
Here, a view that simply displays the top page and a view that returns JSON of user information are defined.
(pipenv)$ python manage.py migrate
(pipenv)$ python manage.py createsuperuser
(pipenv)$ python manage.py runserver
Register the OAuth application in advance to get the client ID and client secret of the application. At that time, also register the callback URL of the web application. To access the provider's settings page, log in to the Admin site once and then log in. http://127.0.0.1:8000/o/applications/ Open and add the OAuth application to be linked.
Setting items | Set value |
---|---|
Name | anything |
client Type | Confidential |
Authorization grant type | Authorization code |
Redirect urls: | http://localhost:8001/accounts/testprovider/login/callback/ |
(Same as above) | http://127.0.0.1:8001/accounts/testprovider/login/callback/ |
Create a user to use when logging in to OAuth. http://127.0.0.1:8000/admin/auth/user/
Create an app that requests authentication and authorization from test_provider.
(pipenv)$ cd test-oauth
(pipenv)$ django-admin.py startproject test_consumer
(pipenv)$ cd test_consumer
test_consumer/settings.py
INSTALLED_APPS = [
#add to
'django.contrib.sites',
'test_consumer',
'allauth',
'allauth.account',
'testprovider',
]
test_consumer/settings.py
AUTHENTICATION_BACKENDS = (
'django.contrib.auth.backends.ModelBackend',
'allauth.account.auth_backends.AuthenticationBackend',
)
SITE_ID = 1
SESSION_COOKIE_NAME = 'test-consumer-session-id'
#Redirect to top page after login
LOGIN_REDIRECT_URL = '/'
Specify the transition destination after authentication with ** LOGIN_REDIRECT_URL **.
test_consumer/urls.py
from django.contrib import admin
from django.urls import path, include
from django.views.generic import TemplateView
urlpatterns = [
path('admin/', admin.site.urls),
path('', TemplateView.as_view(template_name='index.html')),
path('accounts/', include('allauth.urls')),
]
(pipenv)$ mkdir test_consumer/templates
index.html
<!DOCTYPE html>
{% load socialaccount %}
{% load account %}
<html>
<head>
<meta charset="utf-8">
<title>testprovider</title>
</head>
<body>
{% if user.is_authenticated %}
Welcome{% user_display user %}Mr.<br />
{% for sa in user.socialaccount_set.all %}
{{ sa.extra_data }}<br />
{% endfor %}
{% else %}
<a href="{% provider_login_url "testprovider" %}">
Login with Test Provider
</a>
{% endif %}
</body>
</html>
To check the operation, use ** {% if user.is_authenticated%} ** to display the login link when logged out and the user information when logged in.
Inheriting the Provider
class by referring to Implementation of django-allauth for login for various providers Implement the testprovider adapter.
[Addition]
Providers that aren't in providers
of django-allauth
can rewrite this area to create a ** self-made oleore social login feature. ** **
Content-Type
of the access token issuance request,x-www-form-urlencoded Note that there are also formats other than
)!testprovider/provider.py
from allauth.socialaccount import providers
from allauth.socialaccount.providers.base import ProviderAccount
from allauth.socialaccount.providers.oauth2.provider import OAuth2Provider
class TestAccount(ProviderAccount):
def to_str(self):
dflt = super(TestAccount, self).to_str()
return self.account.extra_data.get('name', dflt)
class TestProvider(OAuth2Provider):
id = 'testprovider'
name = 'Test Provider'
account_class = TestAccount
def get_default_scope(self):
return ['read', 'write']
def get_site(self):
settings = self.get_settings()
return settings.get('SITE', 'testprovider')
def extract_uid(self, data):
uid = str(data['user_id'])
return uid
def extract_common_fields(self, data):
return dict(username=data.get('email', 'no name'))
providers.registry.register(TestProvider)
testprovider/urls.py
from allauth.socialaccount.providers.oauth2.urls import default_urlpatterns
from .provider import TestProvider
urlpatterns = default_urlpatterns(TestProvider)
testprovider/views.py
import requests
from allauth.socialaccount.providers.oauth2.views import (OAuth2Adapter,
OAuth2LoginView,
OAuth2CallbackView)
from allauth.socialaccount.providers import registry
from .provider import TestProvider
from django.conf import settings
server_url_prefix = getattr(
settings, 'TEST_PROVIDER_URL_PREFIX',
'http://127.0.0.1:8000')
class TestOAuth2Adapter(OAuth2Adapter):
provider_id = TestProvider.id
access_token_url = server_url_prefix + '/o/token/'
authorize_url = server_url_prefix + '/o/authorize/'
profile_url = server_url_prefix + '/api/profile/'
def complete_login(self, request, app, token, **kwargs):
provider = registry.by_id(app.provider)
resp = requests.get(self.profile_url,
params={'access_token': token.token})
extra_data = resp.json()
return self.get_provider().sociallogin_from_response(
request, extra_data)
oauth2_login = OAuth2LoginView.adapter_view(TestOAuth2Adapter)
oauth2_callback = OAuth2CallbackView.adapter_view(TestOAuth2Adapter)
(pipenv)$ python manage.py migrate
(pipenv)$ python manage.py createsuperuser
(pipenv)$ python manage.py runserver 8001
http://127.0.0.1:8001/admin Click + Add in [SOCIAL ACCOUNTS]> [Social applications] Set the "client ID" and "client secret" of the application registered on the test_provider side
Setting items | Set value |
---|---|
Provider | Test Provider |
Name | Test Provider |
Client id | The Client id I just created |
Secret key | Secret key I made earlier |
Key | Sky |
Sites | example.Select com |
http://127.0.0.1:8001 Log in as the test user you created earlier with a browser different from the one you logged in with test_provider.
[Login with Test Provider]> "Authorize"
If the ID linkage is successful, the redirect destination http://127.0.0.1:8001 after successful login set in ** test_consumer / settings.py ** will be redirected, and the user information that was not seen in the logout state will be displayed. It is supposed to be displayed.
Next, I'm going to develop this content to create a social login function for service providers that is not provided by ** django-allauth **.
Recommended Posts