在PostgreSQL中解码Django会话

目录

Django中的会话

会话架构

构建查询

第一眼

从Base64解码

编码为文本

提取JSON

JSON验证

JSON转换

字符串清理

最终查询

使用物化视图进行快速查询

概括


Django中的会话

会话是任何基于HTTPWeb框架的重要组成部分。它们允许Web服务器跟踪重复HTTP客户端的身份,而无需它们对每个请求重新进行身份验证。有几种不同的方法可以跟踪会话。有些不需要服务器保留会话数据(如JSON Web Tokens),而有些则需要。

Django是一种流行的基于PythonWeb框架,附带一个默认会话后端,用于存储持久会话数据。有多种存储和缓存选项;您可以选择简单地将会话存储在SQL数据库中并每次查找它们,将它们存储在像RedisMemcached这样的缓存中,或者使用两者,并在数据库存储之前设置缓存引擎。如果您使用最终将会话存储在 SQL 中的选项之一,则该django_session表将包含您用户的会话。

会话架构

在细读应用程序的数据时,您可能会遇到一个问题,需要您将用户的会话数据链接到他们的实际用户条目(auth_user表)。这最近发生在我身上,当我查看会话表的模式定义时,我很惊讶它没有存储为列user_id。关于为什么会这样,有一些重要的设计决策,但这对像我这样的SQL用户来说很不方便。

session_key是提供客户的关键。通常,发出请求的客户端会将session_key包含在cookie中。当Web服务器收到请求时,它会查找session_key,如果存在,则查询以查看密钥是否已知。如果是,它将查看相关联session_data并检索有关用户及其会话的元数据。

这就是您能够访问Django请求中的request.user内容的方式。user_id从解码的session_data中获取,根据存储的user_id填充内置的User对象,然后该User对象可在整个项目的视图中使用。

一些快速的谷歌搜索向我展示了默认情况下会话数据存储为JSON。我已经意识到Postgres出色的JSON能力,所以我怀疑这是我们可以在Postgres范围内使用的东西。对于像我这样在Postgres上花费大量时间的人来说,这是个好消息。

构建查询

第一眼

正如您在第一张图片中看到的,session_data它似乎不是JSON。存储为JSON的元数据隐藏在base64 编码后面。幸运的是,我们可以在Postgres中轻松解码base64

Base64解码

这几乎没有可读性。我们需要将二进制数据转换为文本。

编码为文本

Postgres中的encode函数允许您将二进制数据编码为文本表示

现在,我们终于可以看到人类可读的东西了。以下是文本格式的完整解码结果之一:

11fcbb0d460fd406e83b60ae082991818a1321a4:{"_auth_user_hash":
"39308b9542b9305fc038d28a51088905e14246a1","_auth_user_backend":"x.alternate_auth.Backend",
"_auth_user_id":"52135"}

提取JSON

我们这里有一个以冒号和各种散列开头的JSON blob。我们只对JSON blob感兴趣。仅提取经过哈希和冒号的文本的一种快速方法是找到第一个冒号的位置并提取其后的所有字符。

为了实现这一点,我们可以同时使用RIGHT函数(返回string末尾的n个字符)POSITION函数(返回字符串中字符的位置)POSITION将只返回您正在搜索的第一个string实例的位置。

RIGHT函数接受一个负索引。负索引从右侧提取字符,string排除了负索引指示的字符。

为了进一步构建此查询,我们将使用CTE将其分为2个部分。当您构建并选择了一个重要的列并且需要多次使用它时,CTE会很有帮助。如果我们只继续一个SELECT,我们将不得不多次键入该encode(decode(session_data, 'base64'), 'escape')部分。这很麻烦,如果您决定更改解析编码数据的方式,则必须在2个地方更改函数调用。

这是我们更新的查询,它提取了JSON部分。

完整结果示例:

{"_auth_user_hash":"396db3c0f4ba3d35b350a",
"_auth_user_backend":"x.alternate_auth.Backend","_auth_user_id":"52646"}</code>

JSON验证

现在该列可以解析为JSON,我们可以继续。但是,如果您在Postgres中尝试将文本转换为JSON而文本不是有效的JSON,则Postgres将抛出错误并停止您的查询。在我的数据库中,某些会话无法解析为JSON。这是一种快速确保文本看起来像可解析的JSON的方法。

where
    substring(decoded, position(':' in decoded) + 1, 1) = '{'
    and right(decoded, 1) = '}'`

任何string不以花括号开头和结尾的都将被过滤掉。

这并不能保证它能够解析,但对于我的数百万个会话的数据库,它完成了这项工作。您可以编写自定义函数来验证JSON可解析性,但速度会较慢。

JSON转换

使用WHERE排除无效会话元数据的子句,是时候将我们的string类型转换为PostgresJSON类型并从JSON中提取_auth_user_id密钥。根据您的Django配置,此键可能不同。将对象转换为JSON类型后,您可以使用object->'key'语法通过键查询JSON值。

字符串清理

我们越来越近了!当从JSON转换为text时,Postgres在它周围添加双引号。最终,我们希望该user_id字段是int,但Postgres不会将包含双引号的string解析为int。甚至JavaScript也不允许!

TRIMBOTH函数将从string的两端剥离指定的字符,留给我们用干净的string,其可以很容易被铸造成一个整数。

最终查询

这是修剪多余的双引号并转换为int.

现在,如示例结果所示,我们已链接session_keyDjango auth_userid

以下是可复制形式的完整查询:

with step1 as (
  select
    session_key,
    encode(decode(session_data, 'base64'), 'escape') :: text as decoded
  from
    django_session
)
select
  session_key,
  trim(
    both '"'
    from
      (
        right(
          decoded,
          0 - position(':' in decoded)
        ) :: json -> '_auth_user_id'
      ) :: text
  ) :: int as user_id
from
  step1
where
  substring(decoded, position(':' in decoded) + 1, 1) = '{'
  and right(decoded, 1) = '}'

使用物化视图进行快速查询

如果您的数据库有很多用户,您会注意到此查询非常慢。创建物化视图将允许您从持久视图重复查询结果,而无需重新运行SQL

当您创建物化视图时(以及随时刷新它),视图的源代码将运行,并将用结果中的行填充它。当您需要最新数据时,请务必刷新视图!

create materialized view mv_django_session_user as
with step1 as (
…

刷新:

refresh materialized view mv_django_session_user;

概括

Postgres中的编码和字符串操作比PythonRubyPHPWeb应用程序使用的常用语言要繁琐一些,但是完全在Postgres中构建一个视图以快速提取所需的确切数据是非常令人满意的并允许您直接加入其他表。

下次你需要提取由web框架或其他第三方编码的数据时,请检查Postgres的答案!

https://www.codeproject.com/Articles/5298141/Decoding-Django-Sessions-in-PostgreSQL

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值