Django,Djoser 社交身份验证:在服务器端会话数据中找不到状态。状态码 400

Posted

技术标签:

【中文标题】Django,Djoser 社交身份验证:在服务器端会话数据中找不到状态。状态码 400【英文标题】:Django, Djoser social auth : State could not be found in server-side session data. status_code 400 【发布时间】:2021-05-18 03:53:15 【问题描述】:

我正在用 django 实现一个身份验证系统并做出反应。这两个应用程序分别运行在 8000、3000 端口。我已经使用 Djoser 包实现了身份验证系统。这个包使用了一些依赖项 social_core 和 social_django。一切似乎都配置好了。我点击登录 google 按钮...我被重定向到 google 登录页面,然后使用 statecode 返回到端口 3000 的前端反应应用程序url 上的参数。

此时我将这些参数发布到后端。后端尝试使用 (social_core/backends/oauth.py) 中的以下代码验证状态密钥是否存在于会话存储中

def validate_state(self):
        """Validate state value. Raises exception on error, returns state
        value if valid."""
        if not self.STATE_PARAMETER and not self.REDIRECT_STATE:
            return None
        state = self.get_session_state()
        request_state = self.get_request_state()
        if not request_state:
            raise AuthMissingParameter(self, 'state')
        elif not state:
            raise AuthStateMissing(self, 'state')
        elif not constant_time_compare(request_state, state):
            raise AuthStateForbidden(self)
        else:
            return state

此时由于某些原因,状态会话密钥不存在。我收到一条错误消息,指出在会话数据中找不到状态(以下错误)

"error":["State could not be found in server-side session data."],"status_code":400

我回顾了我所做的所有动作:

    给后端生成的前端请求给提供者 google-oauth2 一个重定向 url。通过此操作,还会生成 url,状态键也存储在具有特定值 (google-oauth2_state) 的会话中。 前端接收url并重定向到google auth页面。 通过 google 进行身份验证并使用 url 上的 statecode 参数重定向回前端。 前端获取数据表单url,将数据post到后端,验证接收到的状态与点(1)上生成的状态是否相等。

由于某些原因,状态代码没有持久化...任何想法和帮助将不胜感激。

谢谢大家。

【问题讨论】:

如果您发布演示代码,它有助于找出问题。 您解决了这个问题吗?也发生在我身上!但在我的情况下,服务器和客户端的 URL 不同,所以我猜会话存储会导致问题,但不知道如何解决它!任何帮助。 我想知道这是否可以使用 nginx 来解决,就像作者在这里所做的那样:medium.com/swlh/… 我在 localhost:3000 上运行了 React 前端,在 8000 上运行了后端。这发生在会话数据没有发送到 localhost:8000 时。不幸的是,我仍然不知道如何将会话数据从 localhost:3000 发送到 localhost:8000。所以暂时,我使用npm run build 构建反应前端并在Django 中使用collectstatic 命令。然后从同一个端口(localhost:8000)运行前端。现在会话数据正在自动发送,一切对我来说都很完美。 【参考方案1】:

没有必要的详细信息,我只能说出两个可能的原因:

    您使用不正确的session 操作覆盖了后端(或者用户在身份验证完成之前已注销)。 前端使用了错误的state参数

您可以在没有前端的情况下测试社交登录,假设您尝试使用 Google 登录:

    在浏览器中输入社交登录网址,如domain.com:8000/login/google-oauth2/ 授权 查看页面是否正确重定向到您的默认登录页面

如果是,那么可能你需要检查你的前端代码,如果不是,那么检查你的后端代码。

最后,如果您对潜在风险不那么敏感,您还可以覆盖GoogleOAuth2 类,如下所示禁用状态检查:

from social_core.backends import google

class GoogleOAuth2(google.GoogleOAuth2):
    STATE_PARAMETER = False

【讨论】:

【参考方案2】:

我认为您可能需要对第 3 步和第 4 步中的授权流程进行一些更改。

3. 使用 google 进行身份验证,并在 url 上使用状态和代码参数重定向回前端。 4.前端获取数据表单url,将数据post到后端,验证接收到的状态与点(1)上生成的状态是否相等。

也许你应该在谷歌授权后重定向回服务器端。

然后在服务器端进行检查!验证状态和代码(也许做更多的事情)。

然后让服务器重定向到你之前想要的前端站点。

由于某种原因,直接重定向到前端会错过参数.. :-)

【讨论】:

你能试着用codepen或一些代码解释一下吗?文档非常清楚地指出,执行此操作的一般方法是从前端发出发布请求,但由于会话 ID 不匹配/从未添加或类似,请求失败。【参考方案3】:

好的,所以这是您使用社交身份验证时的常见问题。遇到同样的问题很多次了。

流程

    http://127.0.0.1:8000/auth/o/google-oauth2/?redirect_uri=http://localhost:3000/ 发出请求(示例)

    您将收到authorization_url。如果您在此 authorization_url 中注意到存在一个状态。这是“服务器端的状态”。

    现在您需要点击authorization_url 链接。然后您将获得google auth 页面。之后您将被重定向到带有状态和代码的重定向url。请记住,此状态应与服务器端状态相同。(2)

    http://127.0.0.1:8000/auth/o/google-oauth2/?state=''&code='' 发送请求。 如果你的状态不一样,那么你会遇到一些问题。

每次您想登录时,您都需要向http://127.0.0.1:8000/auth/o/google-oauth2/?redirect_uri=http://localhost:3000/ 提出请求 然后到http://127.0.0.1:8000/auth/o/google-oauth2/?state=''&code='' 这样你就会得到同样的状态。

【讨论】:

你能发布一个代码笔吗?文档中解释的方法是使用状态和代码从前端发出后请求,但这会导致上面提到的错误,因为会话 ID 或其他一些解释不匹配。【参考方案4】:

允许 Axios 在前端维护会话

import axios from "axios";
axios.defaults.withCredentials = true;

axios.get("url")
.then(response =>  
   console.log(response) 
)
.catch(error => 
    console.log(error);
);

axios.defaults.withCredentials = true;

CORS_ORIGIN_ALLOW_ALL = 真

CORS_ALLOW_CREDENTIALS = 真

【讨论】:

以上是关于Django,Djoser 社交身份验证:在服务器端会话数据中找不到状态。状态码 400的主要内容,如果未能解决你的问题,请参考以下文章

DRF:如何将 django-rest-framework-jwt 集成到 Djoser

如何覆盖 Djoser 基本端点用户/我

使用 Djoser 和 Django Rest Framework 激活帐户

Django中的Python社交身份验证,makemigrations检测到没有变化

Django REST to React - 无需密码即可获取社交身份验证令牌

Djoser 用户激活电子邮件 POST 示例