Изначально при создании сайта решил использовать архитектуру
REST API для этого применяю
DRF. И если брать обычную ситуацию где со стороны фронта идет запрос на бек - забираются какие-то данные - выводятся на тем же фронтом, то всё понятно. Но вот пример с авторизацией не совсем понятен. Допустим есть кнопка "войти" при нажатии на которую отправляется запрос на бек и он должен что-то вернуть - чтобы фронт проверил и как бы "авторизировал" пользователя (изменил интерфейс страницы как для авторизированого пользователя). Знаю что для
DRF есть модуль
djangorestframework-simplejwt который как бы помогает с авторизацией, но опять же вообще не понимаю как это должно работать, так сказать не вижу всей картины, архитектуры как это должно происходить. Пример на реальном проекте: опять же фронт и бек разделены и на
DRF пишутся только ендпоинты для запросов. И вот есть та самая кнопка
Войти при нажатии на которую - отправляется
GET запрос на получение сгенерированной ссылки авторизации через
Discord, выглядит она следующим образом:
https://discord.com/api/oauth2/authorize/?response...
client_id - id специального бота
redirect_url - страница на которую произойдет редирект после авторизации
scope - не знаю как описать одним словом, но в общем то что вы хотите получить от пользователя
state - специальный хеш, так как я ранее говорил что ссылка генерируется беком - то это мера предосторожности от спама запросами. То есть человек нажимает
Войти - генерируется эта ссылка с этим уникальным хешем и я сохраняю его в сессии для дальнейшей проверки на валидность.
После подтверждение авторизации со стороны пользователя его перекидывает на страницу из ранее сказанного
redirect_url. И это также очередной ендпоинт который обрабатывает запрос и должен внутри себя проверь валидность хеша (
state) и зарегистрировать или авторизировать пользователя. И вот как раз с этим возникли трудности, не понимаю как это должно между собой работать. Текущий код следующий:
import json
import secrets
import requests
from urllib.parse import urlencode
from django.conf import settings
from rest_framework.views import APIView
from django.contrib.auth import authenticate
from django.http import HttpRequest, JsonResponse,\
HttpResponseBadRequest, HttpResponseRedirect
from rest_framework_simplejwt.tokens import RefreshToken
class GenerateDiscordAuthURLView(APIView):
def get(self, request: HttpRequest):
state = secrets.token_urlsafe()
request.session['state'] = state
params = {
'client_id': settings.CLIENT_ID,
'redirect_uri': settings.REDIRECT_URL,
'scope': 'identify email guilds', 'state': state}
url = ('https://discord.com/api/oauth2/authorize?'
f'response_type=code&{urlencode(query=params)}')
return JsonResponse({'auth_url': url})
class GetAuthorizationCodeView(APIView):
def get(self, request: HttpRequest, *args, **kwargs):
request_state = request.GET.get('state')
authorization_code = request.GET.get('code')
session_state = request.session.pop('state', None)
# Проверка параметра state для защиты от CSRF-атак
if not request_state or request_state != session_state:
return HttpResponseBadRequest('Invalid state parameter')
# Проверка наличия кода авторизации
if not authorization_code:
return HttpResponseBadRequest('Authorization code not provided')
data = {
'grant_type': 'authorization_code',
'code': authorization_code,
'redirect_uri': settings.REDIRECT_URL
}
headers = {'Content-Type': 'application/x-www-form-urlencoded'}
response = requests.post(settings.GET_USER_TOKEN_URL, data=data,
headers=headers, auth=(settings.CLIENT_ID, settings.CLIENT_SECRET))
print(response)
if response.status_code != 200:
return HttpResponseBadRequest('Unknown Error')
access_token = response.json()['access_token']
headers = {'Authorization': f'Bearer {access_token}'}
response = requests.get(settings.GET_USER_DATA_URL, headers=headers)
print(response)
user_data = response.json()
user = authenticate(request, data=user_data)
if user:
refresh = RefreshToken.for_user(user)
access_token = str(refresh.access_token)
refresh_token = str(refresh)
# Кодирование данных пользователя в JSON и сохранение в куки
user_data_json = json.dumps(user_data)
response = HttpResponseRedirect('http://127.0.0.1:5500/index.html')
response.set_cookie('access_token', access_token, httponly=True)
response.set_cookie('refresh_token', refresh_token, httponly=True)
response.set_cookie('user_data', user_data_json)
return response
else:
return HttpResponseBadRequest('Authentication failed')