首页 > 解决方案 > Django+React:对从 React 到 Django 后端的 API 请求正确实施身份验证和安全性的最佳方法是什么

问题描述

我正在做一个Django+React项目。我的 React 应用程序是我的only UI renderer(这意味着 Django 不提供模板或任何标记),而我的 Django 应用程序仅用于serving APIs我访问我的数据库资源。

在一个特定的 React 页面上,我的 Django 后端中有一个向 a 发送请求的按钮logintestDRF API

登录 API 视图

class AuthLogin(generics.GenericAPIView):
    serializer_class = LoginSerializer
    authentication_classes = [SessionAuthentication]
    permission_classes = ()

    def get(self, request):
        user = request.user
        if not user and not user.is_authenticated or user.is_anonymous:
            return Response(
                {
                    "status": True,
                    "message": "Login page accessed"
                }, status=status.HTTP_200_OK
            )
        else:
            return Response(
                {
                    "status": False,
                    "message": "You are currently logged in"
                }, status=status.HTTP_400_BAD_REQUEST
            )

    def post(self, request, *args, **kwargs):
        res = []
        res_stat = status.HTTP_401_UNAUTHORIZED
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=False)
        validated_data = serializer.validated_data

        if validated_data:
            user = dj_auth(username=request.data.get('username'),
                           password=request.data.get('password'))

            if user and user.is_authenticated and not user.is_anonymous:
                auth_login(request, user)
                res_stat = status.HTTP_200_OK
                res = {
                    "status": True,
                    "message": "Login successful!",
                    "login": {
                        "date_time": timezone.now(),
                        "user": {
                            'id': user.id,
                            'first_name': user.first_name,
                            'last_name': user.last_name,
                            'email': user.email,
                        }
                    }
                }
            else:
                res_stat = status.HTTP_401_UNAUTHORIZED
                res = {
                    "status": False,
                    "message": "Invalid username and/or password"
                }
        else:
            res_stat = status.HTTP_401_UNAUTHORIZED
            res = {
                "status": False,
                "message": "Invalid username and/or password"
            }
        return Response(res, status=res_stat)

测试 API 视图

class Test(APIView):
    authentication_classes = [SessionAuthentication]
    permission_classes = [IsAuthenticated]

    def post(self, request, *args, **kwargs):
        if request.user and request.user.is_authenticated and not request.user.is_anonymous:
            return Response({
                "test": "coolsss",
                "user": request.user.id
            }, status=status.HTTP_200_OK)
        else:
            return Response({
                "error": "Mind to login first?"
            }, status=status.HTTP_401_UNAUTHORIZED)

到目前为止,在上述 API 上的 Django+React 集成方面做得很好。但是,我注意到了一个安全问题,我不完全确定如何继续前进。

我在隐身浏览器窗口中进行了测试。但是,我也在Postman. 我注意到的是,在使用相同的csrftokensessionidcookie 对 Postman 进行测试之前,我已经关闭了我的隐身浏览器。当我关闭浏览器时,我认为会话已被销毁,因为它处于隐身状态。

现在,当我在 Postman 中运行相同的程序时,test端点仍在进行身份验证、识别用户并返回肯定响应。我不确定这是否应该发生,以及应该使用什么方法来解决这个问题。

我看到这将是一场噩梦的一个示例场景是,Kate 登录并离开她的工作站一分钟。她的同事 John 潜入她的浏览器并窃取了她当前会话csrftokensessionidcookie 值。

凯特回来了,出于某种原因关闭了她的浏览器。John 在他自己的计算机上使用 Postman 向一个 API 发出了一些 POST 请求,Kate 使用他窃取的令牌和 sessionid 来访问该 API。

由于身份验证中的这个问题session/cookie-based,我正在考虑实施token-based身份验证,即使login视图更适合通过服务器会话和 csrftoken cookie 进行身份验证。

但是,如果我使用基于令牌的,我也会将该令牌存储在本地存储中,以便 React 知道用户仍处于登录状态,并将该令牌用于后续请求。但是话又说回来,极客总是可以使用开发工具并潜入本地存储中的该令牌值。

我非常纠结于如何在后端正确实现身份验证和安全性,同时保持用户登录状态的前端。

标签: djangoreactjssessiondjango-rest-framework

解决方案


基于令牌(例如 JWT)是将服务器端服务集成到客户端应用程序的首选选项。至于您面临的问题,最简单的选择是向令牌添加过期选项,这可能仍然不是所有场景的解决方案。

事实是,当您创建客户端应用程序时,客户端拥有控制权,您对此无能为力。保护令牌与保护用户应该考虑的密码相同。您能做的最多就是让其他人更难能够简单地获取令牌并在其他地方使用它。

您可以制作客户端必须生成的具有不同规格的多个令牌,如果所有令牌都匹配,那么您可以为请求提供服务。但同样,这只是让其他人更难复制请求并非不可能。

如果它是一个很难反编译的编译应用程序,并且结合了一些方法,比如使用一些也安全存储在客户端系统中的证书文件,你可以更加确定你的请求的安全性,但是 JS 太简单了阅读和复制。


推荐阅读