如何使用第三方 CAS 身份验证从独立反应前端与 django 后端(相同域,不同端口)验证用户?
How to authenticate user from standalone react frontend with django backend (same domain, different ports), using a third-party CAS authentication?
我正在使用 Django REST framework
设置一个 django 后端以提供 API,并通过第三方 CAS 服务器实现身份验证。目前我的后端认证已经成功实现(使用django-cas-ng
包),也就是说我可以为不同的用户组实现不同的权限。默认情况下,django 后端通过 localhost:8000
服务。
添加一个独立的反应前端(localhost:3000
默认情况下)似乎使身份验证系统复杂化。从3000端口发送到8000端口的请求(axios实现)无法认证
我已经尝试 npm run build
构建静态文件并将它们与 django 集成。在同一个 8000 端口内,所有身份验证和权限都可以正常工作。
谁能建议如何通过不同的端口实现身份验证?
通过发出跨端口请求,您正在破坏浏览器的 Same-origin policy。这样做是出于安全原因。
浏览器还允许您通过设置名为 CORS 的东西来绕过此策略。基本上,您必须从后端 return 调用 Access-Control-Allow-Origin
的 header 来告诉浏览器您信任传入的源。
有关详细信息,您可以阅读链接页面。
在开发过程中,我使用这些设置来监听跨域请求:
# It may be a good idea to use appropriate values during production
ALLOWED_HOSTS = ['*']
CSRF_TRUSTED_ORIGINS = ['*'] # if you're serving your frontend
# and backend under same domain and port
# during production, then you can remove
# this.
然后我还有一个中间件,它在每个 HTTP 请求中注入所需的 CORS header。
如果您在同一域和端口上为前端和后端提供服务,则不需要这样做。所以最好不要在生产过程中使用这个中间件。如果必须,请使用适当的值。
我将此代码保存在名为 middleware.py
的文件中,并将此文件保存在与我的 settings.py
文件相同的目录中。
# project_name/project_name/middleware.py
from django.http import HttpResponse
from django.conf import settings
CORS_ALLOW_ORIGIN = getattr(settings, 'CORS_ALLOW_ORIGIN', '*')
CORS_ALLOW_METHODS = getattr(settings, 'CORS_ALLOW_METHODS', ['POST', 'GET', 'PUT', 'DELETE', 'OPTIONS', 'PATCH'])
CORS_ALLOW_HEADERS = getattr(settings, 'CORS_ALLOW_HEADERS', ['content-type', 'authorization'])
CORS_ALLOW_CREDENTIALS = getattr(settings, 'CORS_ALLOW_CREDENTIALS', True)
CORS_EXPOSE_HEADERS = getattr(settings, 'CORS_EXPOSE_HEADERS', ['content-type', 'location'])
class CorsMiddleware:
def __init__(self, get_response):
self.get_response = get_response
def set_headers(self, response):
response['Access-Control-Allow-Origin'] = CORS_ALLOW_ORIGIN
response['Access-Control-Allow-Methods'] = ','.join(CORS_ALLOW_METHODS)
response['Access-Control-Allow-Headers'] = ','.join(CORS_ALLOW_HEADERS)
response['Access-Control-Allow-Credentials'] = 'true' if CORS_ALLOW_CREDENTIALS else 'false'
response['Access-Control-Expose-Headers'] = ','.join(CORS_EXPOSE_HEADERS)
return response
def __call__(self, request):
response = self.get_response(request)
response = self.set_headers(response)
return response
最后,更改一些设置以告诉 Django 使用此中间件:
MIDDLEWARE = [
# ... other middlewares ...
'project_name.middleware.CorsMiddleware',
]
重要提示:如果您在同一域和端口下为前端和后端提供服务,则在生产中可能不需要此答案中的任何代码。但是了解更多关于 CORS 的知识仍然是个好主意。
原来是因为从 localhost:3000
发送到 localhost:8000
的请求不包含来自 cookie 的 sessionid
,所以用户将无法通过身份验证。
对于 axios,设置 withCredential
选项将包括 HTTPOnly sessionid
:
axios("example.com", {
method: "post",
data: someJsonData,
withCredentials: true
})
对于 django 端,响应将需要包括:
Access-Control-Allow-Credentials: true,
Access-Control-Allow-Methods GET, POST, PUT, PATCH, DELETE, OPTIONS,
Access-Control-Allow-Headers Content-Type
Access-Control-Allow-Origin: http://localhost:3000
// CORS_ALLOW_ORIGIN = ['*'] or CORS_ORIGIN_ALLOW_ALL = True will not work
再次感谢@xyres 提供 CORS 信息,它对解决这个问题真的很有帮助!
我正在使用 Django REST framework
设置一个 django 后端以提供 API,并通过第三方 CAS 服务器实现身份验证。目前我的后端认证已经成功实现(使用django-cas-ng
包),也就是说我可以为不同的用户组实现不同的权限。默认情况下,django 后端通过 localhost:8000
服务。
添加一个独立的反应前端(localhost:3000
默认情况下)似乎使身份验证系统复杂化。从3000端口发送到8000端口的请求(axios实现)无法认证
我已经尝试 npm run build
构建静态文件并将它们与 django 集成。在同一个 8000 端口内,所有身份验证和权限都可以正常工作。
谁能建议如何通过不同的端口实现身份验证?
通过发出跨端口请求,您正在破坏浏览器的 Same-origin policy。这样做是出于安全原因。
浏览器还允许您通过设置名为 CORS 的东西来绕过此策略。基本上,您必须从后端 return 调用 Access-Control-Allow-Origin
的 header 来告诉浏览器您信任传入的源。
有关详细信息,您可以阅读链接页面。
在开发过程中,我使用这些设置来监听跨域请求:
# It may be a good idea to use appropriate values during production
ALLOWED_HOSTS = ['*']
CSRF_TRUSTED_ORIGINS = ['*'] # if you're serving your frontend
# and backend under same domain and port
# during production, then you can remove
# this.
然后我还有一个中间件,它在每个 HTTP 请求中注入所需的 CORS header。
如果您在同一域和端口上为前端和后端提供服务,则不需要这样做。所以最好不要在生产过程中使用这个中间件。如果必须,请使用适当的值。
我将此代码保存在名为 middleware.py
的文件中,并将此文件保存在与我的 settings.py
文件相同的目录中。
# project_name/project_name/middleware.py
from django.http import HttpResponse
from django.conf import settings
CORS_ALLOW_ORIGIN = getattr(settings, 'CORS_ALLOW_ORIGIN', '*')
CORS_ALLOW_METHODS = getattr(settings, 'CORS_ALLOW_METHODS', ['POST', 'GET', 'PUT', 'DELETE', 'OPTIONS', 'PATCH'])
CORS_ALLOW_HEADERS = getattr(settings, 'CORS_ALLOW_HEADERS', ['content-type', 'authorization'])
CORS_ALLOW_CREDENTIALS = getattr(settings, 'CORS_ALLOW_CREDENTIALS', True)
CORS_EXPOSE_HEADERS = getattr(settings, 'CORS_EXPOSE_HEADERS', ['content-type', 'location'])
class CorsMiddleware:
def __init__(self, get_response):
self.get_response = get_response
def set_headers(self, response):
response['Access-Control-Allow-Origin'] = CORS_ALLOW_ORIGIN
response['Access-Control-Allow-Methods'] = ','.join(CORS_ALLOW_METHODS)
response['Access-Control-Allow-Headers'] = ','.join(CORS_ALLOW_HEADERS)
response['Access-Control-Allow-Credentials'] = 'true' if CORS_ALLOW_CREDENTIALS else 'false'
response['Access-Control-Expose-Headers'] = ','.join(CORS_EXPOSE_HEADERS)
return response
def __call__(self, request):
response = self.get_response(request)
response = self.set_headers(response)
return response
最后,更改一些设置以告诉 Django 使用此中间件:
MIDDLEWARE = [
# ... other middlewares ...
'project_name.middleware.CorsMiddleware',
]
重要提示:如果您在同一域和端口下为前端和后端提供服务,则在生产中可能不需要此答案中的任何代码。但是了解更多关于 CORS 的知识仍然是个好主意。
原来是因为从 localhost:3000
发送到 localhost:8000
的请求不包含来自 cookie 的 sessionid
,所以用户将无法通过身份验证。
对于 axios,设置 withCredential
选项将包括 HTTPOnly sessionid
:
axios("example.com", {
method: "post",
data: someJsonData,
withCredentials: true
})
对于 django 端,响应将需要包括:
Access-Control-Allow-Credentials: true,
Access-Control-Allow-Methods GET, POST, PUT, PATCH, DELETE, OPTIONS,
Access-Control-Allow-Headers Content-Type
Access-Control-Allow-Origin: http://localhost:3000
// CORS_ALLOW_ORIGIN = ['*'] or CORS_ORIGIN_ALLOW_ALL = True will not work
再次感谢@xyres 提供 CORS 信息,它对解决这个问题真的很有帮助!