如何使用第三方CAS身份验证从具有Django后端(相同域,不同端口)的独立React前端对用户进行身份验证?

时间:2019-07-01 06:59:14

标签: django reactjs django-rest-framework cas

我正在使用Django REST framework设置django后端以提供API,并通过第三方CAS服务器实现身份验证。目前,我的后端身份验证已成功实现(使用django-cas-ng包),这意味着我可以为不同的用户组实现不同的权限。 django后端默认通过localhost:8000提供服务。

添加独立的反应前端(默认为localhost:3000)似乎会使身份验证系统复杂化。从3000端口发送到8000端口的请求(由axios实现)无法通过身份验证。

我尝试过npm run build来构建静态文件并将其与django集成。在同一个8000端口中,所有身份验证和权限都可以正常工作。

有人可以建议如何通过不同的端口实施身份验证吗?

2 个答案:

答案 0 :(得分:1)

通过发出跨端口请求,您就破坏了浏览器的Same-origin policy。出于安全原因这样做。

浏览器还可以通过设置称为CORS的方式来绕过此策略。基本上,您必须从后端返回一个名为Access-Control-Allow-Origin的标头,以告诉浏览器您信任传入的源。

有关更多信息,您可以阅读链接的页面。


在开发过程中,我使用以下设置来监听跨域请求:

# 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标头。

如果您在相同的域和端口上提供前端和后端,则不需要此操作。因此,最好不要在生产过程中使用此中间件。如果必须,请使用适当的值。

我将此代码保存在名为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的更多信息仍然是一个好主意。

答案 1 :(得分:0)

原来是因为从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信息,在解决此问题方面确实有很大帮助!