从令牌创建 Django 会话

Posted

技术标签:

【中文标题】从令牌创建 Django 会话【英文标题】:Create Django Session From Token 【发布时间】:2016-08-18 04:10:35 【问题描述】:

问题

我目前正在与从 Django 提供身份验证强制媒体文件这一众所周知的问题作斗争。问题背景很简单:

我们想使用 Django 的媒体文件支持 默认情况下,媒体文件不是私有的。事实上,通常网络服务器会直接为它们提供服务。 我们希望在访问媒体文件时对用户进行身份验证 我们在前端使用令牌认证 由于没有有效会话,浏览器在访问私人文件时无法进行身份验证(例如在新选项卡中打开 PDF) 我们希望 Django 为浏览器提供身份验证,但需要以某种方式使用现有的身份验证令牌进行身份验证 我们仍然希望 nginx 将文件发回,因此我们将在身份验证后利用X-Accel-Redirect

尝试解决

到目前为止,我所做的(并且有效)是创建另一个 API 视图,该视图需要令牌身份验证并将文件发回,然后创建一个 Angular 指令来用 blob 替换所有受保护的 URL。当用户单击链接时,它会使用令牌身份验证获取文件,然后创建一个包含该数据的 blob。然后浏览器会打开该 blob。

很遗憾,无法共享 blob,因此用户无法将这些文件的链接相互粘贴。我想知道是否有办法解决它。

目标

我的目标是使用令牌来创建一个有效的(和短暂的到期)会话。这样,当用户单击链接时,会发送一个请求来检查是否存在有效会话,然后以某种方式配置浏览器以便它可以使用该会话。整个过程会是这样的:

用户点击链接(这实际上是一个更复杂的角度指令) Angular 向服务器发起会话请求 服务器响应必要的信息 使用 javascript 配置浏览器会话 强制浏览器打开与新建立会话的链接 根据会话验证用户,使用标头将文件发送到 nginx

我不是在寻找实施的答案,我可以自己处理细节。我更感兴趣的是获得有关如何以最佳方式完成此操作的反馈。即:

如何根据 API 响应中的一些会话信息配置浏览器? 我应该如何处理过期这些会话以确保其安全 我应该如何建立这个会话?每次点击链接时检查/创建会话是否合理(假设这里的流量不是问题) 这是一个合理的跨浏览器解决方案吗?有没有更好的办法? 当文件 URL 与没有会话但具有有效令牌的用户共享时,如何使用中间页面建立此会话?

一些选项

更新:我与一些同事交谈过,他们提出了以下选项:

让 API 检索单次使用或短期到期令牌,而不是会话,并将其作为查询参数附加到文件的 URL。在请求中验证这一点。这可行,但仍然不允许共享 URL。 在登录时建立会话。如果在用户尝试访问文件时该会话已过期,则重定向到会话登录,然后在通过身份验证时重定向回该文件。这也有效,但我想避免额外的身份验证步骤,因为令牌的有效期很长,而会话的有效期很短。给它们同样的过期时间也会有缺点,因为更频繁过期的令牌或过期更少的会话并不理想。

【问题讨论】:

你的最终目标是什么?在用户之间共享文件?用户是否应该在访问文件之前登录?共享链接/文件的规则/条件是什么?用户是否能够/允许共享每个文件?谁可以访问哪些文件以及如何为每个文件设置权限? 用户必须登录才能查看文件。他们通常会预先登录,否则将被重定向到登录。所有用户都可以看到所有文件。目标是进行身份验证,同时仍允许用户将链接粘贴到其他用户。身份验证很容易(如问题中所述)。问题在于身份验证,但仍然允许共享。 如果用户必须登录才能查看文件,是什么阻止您在访问文件之前验证每个用户?我仍然没有 100% 清楚的是authenticate while still allowing users to paste links to other users。认证什么?用户?用户已经登录对吗? paste links to other users 是什么?粘贴在哪里?出于什么目的?不是每个用户都需要登录才能访问文件吗? 用户使用令牌认证“登录”。令牌在每个 API 请求中作为标头发送。当文档(如 PDF)在新选项卡中打开时,浏览器没有该令牌。浏览器需要一个有效的会话,这完全是一种不同类型的身份验证。没有建立会话,因此在新选项卡中打开文件时不会对用户进行身份验证。将链接粘贴到用户是共享文件所必需的。例如,如果用户 A 有一个文件要显示给用户 B,他们可能会通过电子邮件发送一个 URL。两个用户都必须经过身份验证才能看到它。 我认为您过于关注与问题无关的细节。例如,我提到粘贴的唯一原因是为了展示 blob 的局限性。问题很简单 - 当用户使用令牌自然地进行身份验证时,我应该如何建立浏览器会话,以便浏览器可以请求私有的文件资源。浏览器无法使用通常使用的令牌,因为我无法修改浏览器发送的出站请求的默认标头 - 只能修改通过 Ajax 发送的那些。您熟悉基于令牌的身份验证吗? 【参考方案1】:

您可以简单地将令牌放入 cookie。

这样,浏览器会自动发送到服务器,当用户直接访问可下载的文件时,您可以使用它进行身份验证。

告诉您的 Django 中间件从 cookie 中读取令牌字符串,而不是读取 Authorization: 标头。

【讨论】:

由于令牌的过期频率低于正常会话,这是否有任何安全隐患? cookie 可能存在更长时间。我觉得如果唯一使用这种情况是在验证文件查看时,它应该没问题。这是一个安全的假设吗?网站上的所有地方都使用 SSL。 您可以将cookie的expires值设置一小段时间,这样设置后一定时间就会消失。但话又说回来,无论如何,您可能会将令牌字符串存储在客户端的 localStorage 中,因此有权访问机器的攻击者也可以从那里读取令牌。 second half of this text compares 使用 cookie 或标头令牌的安全利弊。 所以切换到 cookie 对我来说几乎是有意义的,但我想避免担心 CSRF。在这种情况下,我可以只要求所有 API 端点在标头中具有身份验证,而所有其他端点都在 cookie 中具有身份验证。两者都用合理吗? Django 和 Angular 为状态改变(POST、PUT、DELETE)请求内置了 CSRF 保护。【参考方案2】:

我想了解有关此主题的更多信息。

我也从 django 获得了一个令牌,但每次我刷新页面时,用户都会再次登录。我想把它保存在一个cookie中,让用户即使关闭浏览器也能提出请求。

我也想用 csrf 保护来保护它,但我不知道该怎么做。 另外,将令牌作为纯文本保存在 cookie 中是否安全? 我对这个过程有很多疑问。

我使用 django 作为后端 API,使用 reactjs 作为前端。

如何让django生成cookie和csrf cookie?

1) 我希望能够使用令牌从浏览器到我的网站进行身份验证(

2) 我也想将此 api 用于移动应用程序吗?那么创建一个cookie,它是否会在移动应用程序身份验证期间产生冲突?

【讨论】:

这不是一个真正的答案,你实际上是在问问题......见the How To Answer section

以上是关于从令牌创建 Django 会话的主要内容,如果未能解决你的问题,请参考以下文章

使用带有令牌而不是 Cookie 的 Django 会话框架?

Django + JSON Web 令牌 + 禁用基于会话的授权

创建会话时如何检测过期的访问令牌?

无模板 Django + AJAX:Django 的 CSRF 令牌是不是在浏览会话过程中更新?

从 SID 创建用户令牌,在用户上下文中展开环境变量

Django Rest 框架中的基于会话的与令牌身份验证