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 登录页面,然后使用 state 和 code 返回到端口 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 上的 state 和 code 参数重定向回前端。
前端获取数据表单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 和 Django Rest Framework 激活帐户
Django中的Python社交身份验证,makemigrations检测到没有变化