Use Discord oauth to log in

This commit is contained in:
Yohann D'ANELLO 2020-11-16 03:33:48 +01:00
parent 74d8d7f989
commit 358f8d446a
4 changed files with 105 additions and 6 deletions

78
lglog/middlewares.py Normal file
View File

@ -0,0 +1,78 @@
from authlib.integrations.base_client import OAuthError
from authlib.integrations.django_client import OAuth
from authlib.oauth2.rfc6749 import OAuth2Token
from django.conf import settings
from django.shortcuts import redirect
from django.utils.deprecation import MiddlewareMixin
class OAuthMiddleware(MiddlewareMixin):
def __init__(self, get_response=None):
super().__init__(get_response)
self.oauth = OAuth()
def process_request(self, request):
if settings.OAUTH_URL_WHITELISTS is not None:
for w in settings.OAUTH_URL_WHITELISTS:
if request.path.startswith(w):
return self.get_response(request)
def update_token(token, refresh_token, access_token):
request.session['token'] = token
return None
sso_client = self.oauth.register(
settings.OAUTH_CLIENT_NAME, overwrite=True, **settings.OAUTH_CLIENT, update_token=update_token
)
if request.path.startswith('/oauth/callback'):
self.clear_session(request)
request.session['token'] = sso_client.authorize_access_token(request)
if self.get_current_user(sso_client, request) is not None:
redirect_uri = request.session.pop('redirect_uri', None)
if redirect_uri is not None:
return redirect(redirect_uri)
return redirect("index")
if request.session.get('token', None) is not None:
current_user = self.get_current_user(sso_client, request)
if current_user is not None:
return self.get_response(request)
# remember redirect URI for redirecting to the original URL.
request.session['redirect_uri'] = request.path
return sso_client.authorize_redirect(request, settings.OAUTH_CLIENT['redirect_uri'])
# fetch current login user info
# 1. check if it's in cache
# 2. fetch from remote API when it's not in cache
@staticmethod
def get_current_user(sso_client, request):
token = request.session.get('token', None)
if token is None or 'access_token' not in token:
return None
if not OAuth2Token.from_dict(token).is_expired() and 'user' in request.session:
return request.session['user']
try:
res = sso_client.get(settings.OAUTH_CLIENT['userinfo_endpoint'], token=OAuth2Token(token))
if res.ok:
request.session['user'] = res.json()
return res.json()
raise Exception(res, str(res.__dict__))
except OAuthError as e:
print(e)
return None
@staticmethod
def clear_session(request):
try:
del request.session['user']
del request.session['token']
except KeyError:
pass
def __del__(self):
print('destroyed')

View File

@ -12,10 +12,11 @@ https://docs.djangoproject.com/en/3.1/ref/settings/
from pathlib import Path
from .secrets import OAUTH_CLIENT_ID, OAUTH_CLIENT_SECRET
# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/3.1/howto/deployment/checklist/
@ -27,7 +28,6 @@ DEBUG = True
ALLOWED_HOSTS = []
# Application definition
INSTALLED_APPS = [
@ -39,6 +39,7 @@ INSTALLED_APPS = [
'django.contrib.staticfiles',
'crispy_forms',
'django_openid_auth',
'lg',
]
@ -53,6 +54,7 @@ MIDDLEWARE = [
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'django.middleware.locale.LocaleMiddleware',
'django.contrib.sites.middleware.CurrentSiteMiddleware',
'lglog.middlewares.OAuthMiddleware',
]
ROOT_URLCONF = 'lglog.urls'
@ -75,7 +77,6 @@ TEMPLATES = [
WSGI_APPLICATION = 'lglog.wsgi.application'
# Database
# https://docs.djangoproject.com/en/3.1/ref/settings/#databases
@ -86,7 +87,6 @@ DATABASES = {
}
}
# Password validation
# https://docs.djangoproject.com/en/3.1/ref/settings/#auth-password-validators
@ -105,13 +105,13 @@ AUTH_PASSWORD_VALIDATORS = [
},
]
# Internationalization
# https://docs.djangoproject.com/en/3.1/topics/i18n/
LANGUAGE_CODE = 'en'
from django.utils.translation import gettext_lazy as _
LANGUAGES = [
('en', _('English')),
('fr', _('French')),
@ -125,7 +125,6 @@ USE_L10N = True
USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/3.1/howto/static-files/
@ -141,3 +140,22 @@ STATICFILES_DIRS = [
CRISPY_TEMPLATE_PACK = 'bootstrap4'
DJANGO_TABLES2_TEMPLATE = 'django_tables2/bootstrap4.html'
# OAuth Settings
OAUTH_URL_WHITELISTS = []
OAUTH_CLIENT_NAME = 'discord'
OAUTH_CLIENT = {
'client_id': OAUTH_CLIENT_ID,
'client_secret': OAUTH_CLIENT_SECRET,
'access_token_url': 'https://discordapp.com/api/oauth2/token',
'authorize_url': 'https://discordapp.com/api/oauth2/authorize',
'api_base_url': 'https://discordapp.com/api/',
'redirect_uri': 'http://localhost:8000/oauth/callback',
'client_kwargs': {
'scope': 'identify email',
'token_placement': 'header'
},
'userinfo_endpoint': 'users/@me',
}

View File

@ -6,4 +6,6 @@
{% block content %}
Historique de loup-garou
{{ request.session.user }}
{% endblock %}

View File

@ -1,3 +1,4 @@
authlib~=0.15
Django~=3.1
django-crispy-forms
django-polymorphic~=3.0