Django OAuth Toolkit не получает URI перенаправления

Я использую инструментарий Django OAuth и использую следующий код для реализации OAuth

import requests
from django.http import JsonResponse
from django.shortcuts import redirect, render
from django.contrib.auth import authenticate, login, logout
from django.contrib.auth.decorators import login_required
from .forms import AuthenticationForm, UserProfileForm
from .models import UserProfile
from oauth2_provider.models import get_application_model
import base64
    Application = get_application_model()
    def oauth_login(request):
        app = Application.objects.get(name="App")
        #redirect_uri = request.GET.get("redirect_uri", "http://test.com:8000/callback")
        #redirect_uri = request.GET.get("redirect_uri", "http://test.com:8002/malicious_redirect.html")
        redirect_uri = request.POST.get("redirect_uri", "http://test.com:8002/malicious_redirect.html")
        
        authorization_url = (
            f"http://test.com:8000/o/authorize/?client_id={app.client_id}&response_type=code&redirect_uri={redirect_uri}"
        )
        return redirect(authorization_url)
    
    def oauth_callback(request):
        code = request.GET.get("code")
        
        if not code:
            return JsonResponse({'error': 'missing_code', 'details': 'Missing code parameter.'}, status=400) 
    
        token_url = "http://test.com:8000/o/token/"
        client_id = Application.objects.get(name="App").client_id
        client_secret = Application.objects.get(name="App").client_secret
        #redirect_uri = request.GET.get("redirect_uri", "http://test.com:8002/callback")
        redirect_uri = request.GET.get("redirect_uri", "http://test.com:8002/unique_redirect.html")
        
        data = {
            "grant_type": "authorization_code",
            "code": code,
            "redirect_uri": redirect_uri,
            "client_id": client_id,
            "client_secret": client_secret,
        }
        
        headers = {
            'Content-Type': 'application/x-www-form-urlencoded',
            'Authorization': f'Basic {base64.b64encode(f"{client_id}:{client_secret}".encode()).decode()}',
        }
        
        response = requests.post(token_url, data=data, headers=headers)
        tokens = response.json()
        print(tokens)
        if response.status_code != 200:
            return JsonResponse({'error': 'token_exchange_failed', 'details': tokens}, status=response.status_code)
        
        request.session['access_token'] = tokens['access_token']
        request.session['refresh_token'] = tokens['refresh_token']
        
        return JsonResponse(tokens)
       #return redirect('profile')

Проблема в том, что если я вошел в панель администратора OAuth 2.0 с учетными данными суперпользователя, то приведенный выше код работает нормально и перенаправляет на указанный URL. В противном случае он не работает и использует LOGIN_REDIRECT_URL = '/profile/' из settings.py.

В чем может быть причина?

Надеюсь, у вас все хорошо. Я не эксперт в этом вопросе, и у меня нет средств, чтобы проверить это на себе, но позвольте мне дать вам несколько предложений, которые могут помочь решить проблему.


Первое, что приходит на ум, это то, что Django OAuth Toolkit иногда выполняет проверку авторизации перед разрешением перенаправления. Так что если вы вошли в систему как суперпользователь, у вас есть все права, поэтому все работает. Для других пользователей эта проверка может быть неудачной.

На всякий случай убедитесь, что используемый вами redirect_uri точно соответствует одному из URI, перечисленных в допустимых перенаправлениях клиентского приложения.

Я не думаю, что этим можно было бы пренебречь, но все же проверьте, есть ли у пользователя определенные разрешения (если вы определили диапазоны, то есть.)

О, и вы также можете посмотреть на обработку сеансов, которую вы могли сделать, потому что когда вы не вошли в систему как суперпользователь, приложение может терять информацию о сеансе и переходить по умолчанию к LOGIN_REDIRECT_URL


Я предлагаю сделать следующее, чтобы точно определить проблему:

Записывайте в журнал redirect_uri в различных точках, чтобы убедиться, что передача происходит правильно.

Просмотрите свой settings.py файл, чтобы убедиться, что инструментарий OAuth настроен правильно, а также специально проверьте OAUTH2_PROVIDER настройки.

Вы также можете рассмотреть возможность реализации пользовательского представления входа, которое использует систему аутентификации Django.


Вы можете попробовать что-то вроде этого, чтобы проверить, где именно ваш поток ломается для не-суперпользователей:

@login_required
def oauth_login(request):
    app = Application.objects.get(name="App")
    redirect_uri = request.POST.get("redirect_uri", "http://test.com:8002/malicious_redirect.html")
    
    print(f"User: {request.user}, Redirect URI: {redirect_uri}")
    
    if not request.user.is_authenticated:
        raise PermissionDenied("User must be authenticated")
    
    print(f"Cleared authentication check.")
    
    authorization_url = (
        f"http://test.com:8000/o/authorize/?client_id={app.client_id}&response_type=code&redirect_uri={redirect_uri}"
    )
    print(f"Authorization URL: {authorization_url}")
    return redirect(authorization_url)

В крайнем случае, вы можете заглянуть в исходный код Django OAuth Toolkit, особенно в класс AuthorizationView, чтобы посмотреть, как он работает с перенаправлениями и аутентификацией.


Поскольку у меня нет возможности проверить их самостоятельно, я могу лишь дать несколько предложений, которые вы, возможно, уже пробовали, извините, если это не слишком поможет.

все равно желаю вам удачи и надеюсь, что вы решите свою проблему. 👍

Проблема, с которой вы столкнулись, скорее всего, связана с правами или состоянием аутентификации пользователя, который пытается авторизоваться на сервере OAuth. Когда вы вошли в систему как суперпользователь, у вас есть необходимые разрешения для выполнения операций OAuth. Однако если вы вошли в систему не как суперпользователь, процесс авторизации может не выполняться из-за недостаточных разрешений или из-за того, что пользователь не прошел аутентификацию должным образом.

Вот несколько моментов, которые следует проверить и учесть:

Разрешения и доступ: Убедитесь, что учетная запись, не являющаяся суперпользователем, имеет соответствующие разрешения на доступ к конечным точкам OAuth. Проверьте настройки приложения OAuth и разрешения пользователя.

Состояние аутентификации: Убедитесь, что пользователь аутентифицирован, прежде чем инициировать процесс OAuth. Если пользователь не аутентифицирован, сервер OAuth может перенаправить его на LOGIN_REDIRECT_URL.

Настройки приложения OAuth: Убедитесь, что настройки приложения OAuth (URI перенаправления, идентификаторы клиентов и секреты) правильно настроены для всех пользователей, а не только для суперпользователя.

Обработка ошибок: Улучшите обработку ошибок, чтобы регистрировать и отображать конкретные ошибки, возникающие в процессе OAuth. Это поможет определить точную причину неудачной авторизации для не-суперпользователей.

Вот пересмотренная версия вашего кода с дополнительными проверками и обработкой ошибок:

import requests
from django.http import JsonResponse
from django.shortcuts import redirect, render
from django.contrib.auth import authenticate, login, logout
from django.contrib.auth.decorators import login_required
from .forms import AuthenticationForm, UserProfileForm
from .models import UserProfile
from oauth2_provider.models import get_application_model
import base64

Application = get_application_model()

@login_required
def oauth_login(request):
    app = Application.objects.get(name="App")
    redirect_uri = request.POST.get("redirect_uri", 
"http://test.com:8002/malicious_redirect.html")

authorization_url = (
    f"http://test.com:8000/o/authorize/?client_id= 
   {app.client_id}&response_type=code&redirect_uri={redirect_uri}"
)
return redirect(authorization_url)

@login_required
def oauth_callback(request):
    code = request.GET.get("code")

    if not code:
        return JsonResponse({'error': 'missing_code', 'details': 'Missing code 
    parameter.'}, status=400)

token_url = "http://test.com:8000/o/token/"
app = Application.objects.get(name="App")
client_id = app.client_id
client_secret = app.client_secret
redirect_uri = request.GET.get("redirect_uri", 
"http://test.com:8002/unique_redirect.html")

data = {
    "grant_type": "authorization_code",
    "code": code,
    "redirect_uri": redirect_uri,
    "client_id": client_id,
    "client_secret": client_secret,
}

headers = {
    'Content-Type': 'application/x-www-form-urlencoded',
    'Authorization': f'Basic {base64.b64encode(f"{client_id}: 
   {client_secret}".encode()).decode()}',
}

response = requests.post(token_url, data=data, headers=headers)
tokens = response.json()

if response.status_code != 200:
    return JsonResponse({'error': 'token_exchange_failed', 'details': tokens}, 
status=response.status_code)

request.session['access_token'] = tokens['access_token']
request.session['refresh_token'] = tokens['refresh_token']

return JsonResponse(tokens)

Изменения клавиш:

  1. Добавлен декоратор @login_required для обеспечения аутентификации пользователя перед обращением к представлениям oauth_login и oauth_callback.
  2. Улучшена обработка ошибок для возврата специфических сообщений об ошибках.

Убедитесь, что пользователь вошел в систему и имеет соответствующие разрешения на выполнение действий OAuth. Если проблема не решена, возможно, необходимо проверить журналы провайдера OAuth на предмет наличия ошибок, связанных с правами или аутентификацией.

Вернуться на верх