我正在使用 Django OAuth 工具包并使用以下代码进行 OAuth 实现
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/'
from
settings.py
可能是什么原因?
The issue you are facing is related to how Django OAuth Toolkit handles redirect URIs and its interaction with the Django authentication system.
Here's a breakdown of why the code works with a superuser but not with regular users and how to fix it:
The Problem:
-
Conflicting Redirects: When you log in as a superuser, you're likely already authenticated in the Django admin panel. In this case, Django OAuth Toolkit probably bypasses its internal redirect mechanism since you have an active session. It directly uses the
redirect_uri
provided in youroauth_callback
view. -
LOGIN_REDIRECT_URL
Interference: For non-superuser logins, Django's authentication system kicks in. After a successful OAuth flow, Django sees that the user is now authenticated but doesn't have session data to determine where they should be redirected. This is when it defaults to theLOGIN_REDIRECT_URL
specified in yoursettings.py
.
The Solution:
You can address this problem in a couple of ways:
1. Consistent Redirect Handling within
oauth_callback
:
-
Store Redirect URI in Session: Before redirecting to the authorization URL in
oauth_login
, store the intendedredirect_uri
in the session:python def oauth_login(request): # ... your code ... request.session['oauth_redirect_uri'] = redirect_uri authorization_url = ( f"http://test.com:8000/o/authorize/?client_id={app.client_id}" f"&response_type=code&redirect_uri={redirect_uri}" ) return redirect(authorization_url)
-
Retrieve and Redirect: After successful token exchange in
oauth_callback
, retrieve the stored redirect URI and redirect the user:```python def oauth_callback(request): # ... your code ...
redirect_uri = request.session.get('oauth_redirect_uri', '/') # Get from session del request.session['oauth_redirect_uri'] # Clear from session return redirect(redirect_uri)
```
2. Leverage Django OAuth Toolkit's Redirect URI Validation:
- Whitelist Redirect URIs: In your OAuth application settings (either through the admin interface or programmatically), explicitly define a list of allowed redirect URIs for your application.
-
Dynamic Redirect URI Parameter:
Django OAuth Toolkit may support a parameter (e.g.,
state
) that you can pass in the authorization URL to store the redirect URI. This value will be passed back to youroauth_callback
for secure redirection.
Additional Considerations:
- Security: Always validate the redirect URIs received from the client-side to prevent open redirects, which can lead to security vulnerabilities.
- Error Handling: Implement proper error handling for cases where the OAuth flow fails (e.g., invalid code, token exchange errors). Display user-friendly error messages and log the details for debugging.
By implementing one of these solutions, you can ensure that your OAuth flow correctly redirects users to the intended location, regardless of whether they are a superuser or a regular user.
标签:python,django,session,django-oauth,django-oauth-toolkit From: 78796237