Manual Handle OAuth2
# requirement.txt
Django==2.2.6
# auth.py
import json
import requests
from django.conf import settings
from django.contrib import auth
from django.contrib.auth.models import User
from django.http import HttpResponseForbidden, JsonResponse, HttpResponseRedirect
from django.urls import reverse
from common.logger import log
def providers(request):
try:
response = requests.get(f'https://auth.garenanow.com/api/clients/{settings.SEA_AUTH_CLIENT_ID}/providers/')
if response.status_code != 200:
log.warning('status=%s|content=%s', response.status_code, response.content)
content = json.loads(response.content)
if not content['success'] or not content['status_code'] == 200:
raise Exception(content)
except Exception as err:
log.exception(err)
raise
return JsonResponse(content)
def login(request, provider):
try:
redirect_uri = f'{request.scheme}://{request.get_host()}{reverse(callback)}'
state = request.GET.get('state')
if state:
request.session['state'] = state
# Prepare Client Redirect URI
prepare_request = requests.models.PreparedRequest()
prepare_request.prepare_url(
f'https://auth.garenanow.com/api/clients/{settings.SEA_AUTH_CLIENT_ID}/providers/{provider}/login/',
{
'redirect_uri': redirect_uri,
'state': state,
},
)
except Exception as err:
log.exception(err)
raise
return HttpResponseRedirect(prepare_request.url)
def callback(request):
try:
if 'code' not in request.GET:
log.error('request.GET=%s|Seaauth Error', request.GET)
raise Exception('Sea auth error')
session_state = request.session.get('state')
if session_state and session_state != request.GET.get('state'):
log.error(
'request.META=%s|session_state=%s|client_state=%s|Missmatched Client State',
request.META, request.session.get('state'), request.GET.get('state'),
)
raise ValueError('Missmatched Client State')
response = requests.post(
f'https://auth.garenanow.com/api/clients/{settings.SEA_AUTH_CLIENT_ID}/token/',
json.dumps({
'grant_type': 'authorization_code',
'client_secret': settings.SEA_AUTH_CLIENT_SECRET,
'code': request.GET['code'],
}),
)
if response.status_code != 200:
raise Exception('status=%s' % response.status_code)
content = json.loads(response.content)
if not content['success'] or not content['status_code'] == 200:
log.error('content=%s', content)
raise Exception(content)
email = content['user']
log.info('email=%s', email)
user = User.objects.filter(username=email).first()
if not user:
log.error('email=%s|user does not found', email)
return HttpResponseForbidden('Failed to login. User not found.')
if not user.is_active:
log.error('user_id=%s|user is inactive', user.id)
return HttpResponseForbidden('Failed to login. Account disabled.')
auth.login(request, user, backend='django.contrib.auth.backends.ModelBackend')
log.info('user_id=%s|login success', user.id)
except Exception as e:
log.exception(e)
return HttpResponseRedirect(settings.LOGIN_REDIRECT_URL)
# urls.py
from django.contrib.auth.views import logout_then_login
from django.urls import path
from . import views
urlpatterns = [
path('providers/', views.providers),
path('providers/<str:provider>/', views.login),
path('callback/', views.callback),
path('logout/', logout_then_login),
]