jwt支持的django应用程序,用于管理querystring令牌。

django-request-token的Python项目详细描述


django请求令牌

Django应用程序,使用JWT管理一次性和过期的令牌以保护URL。

此应用程序当前需要使用PostgreSQL。

兼容性

此库现在仅限于python3和django1.11及更高版本。

背景

这个项目是由我们在Yunojuno的经验和"过期链接"产生的- 这是一个常见的用例,它为用户提供一个执行单个 操作,可能会绕过标准身份验证。众所周知的用法是 你可以在通讯的底部找到无处不在的"退订"链接。你点击 在链接上,它会立即取消您的订阅,无论您是否 是否已通过身份验证。

如果你在谷歌上搜索"临时网址"、"一次性链接"或类似的东西,你会发现 很多关于支持django的stackoverflow文章-很明显, 您有一个专用的令牌url,并将令牌存储在模型中 如果使用了,则令牌将过期,并且不能再次使用。这很有效,但是 它在许多方面都会下降:

  • 难以支持多个端点(视图)

如果您想支持相同的功能(过期链接)超过 在项目的一个视图中,您要么需要有多个模型和标记 处理程序,或者需要存储特定的视图函数和参数 在模型中;这两种方法都不理想。

  • 难以调试

如果使用具有代理视图函数的单个令牌url视图,则需要 若要存储函数名、参数,则很难支持-when 有人声称他们点击了example.com/t/<;token>;,您无法知道 如果不在数据库中查找的话,这个问题就解决了 为客户支持工作。

  • 难以支持多种方案

一些链接过期,其他的有使用配额-有些两者都有。链接可能是 供单个用户或多个用户使用。

该项目旨在为"标记化"提供一种易于支持的机制 不需要代理视图函数的url-您可以构建格式良好的django URL和视图,然后添加请求令牌支持。

用例

这个项目支持三个核心用例,每个用例都是使用 请求令牌的登录模式属性:

  1. 具有有效载荷的公共链路
  2. 单一身份验证请求
  3. 自动登录

公共链接 requestToken.login_mode_none

在此模式(新令牌的默认设置)中,没有身份验证,也没有 分配的用户。令牌用作附加有效负载的机制 连接到链接。例如,自定义注册或关联链接, 使用从中提取的附加信息呈现标准模板的 代币-例如附属公司的名称,或邀请您参加的人 注册。

# a token that can be used to access a public url, without authenticating# as a user, but carrying a payload (affiliate_id).token=RequestToken.objects.create_token(scope="foo",login_mode=RequestToken.LOGIN_MODE_NONE,data={'affiliate_id':1})...@use_request_token(scope="foo")functionview_func(request):# extract the affiliate id from an token _if_ one is suppliedaffiliate_id=(request.token.data['affiliate_id']ifhasattr(request,'token')elseNone)

单个请求 requestToken.login_mode_request

在请求模式下,request.user属性被指定的用户重写 在令牌中,但仅用于单个请求。这对回应 单一操作(例如rsvp、取消订阅)。如果用户导航到另一个 网页上,它们将不会被验证。如果用户已经 经过身份验证,但作为令牌中的另一个用户,他们将 接收403响应。

# this token will identify the request.user as a given user, but only for# a single request - not the entire session.token=RequestToken.objects.create_token(scope="foo",login_mode=RequestToken.LOGIN_MODE_REQUEST,user=User.objects.get(username="hugo"))...@use_request_token(scope="foo")functionview_func(request):assertrequest.user==User.objects.get(username="hugo")

自动登录 requestToken.login_mode_session

这是核选择,必须极其小心地对待。使用A 会话令牌将自动让用户登录整个会话,给出 单击链接的用户完全访问令牌用户的帐户。这是 用于自动登录。一个很好的例子是电子邮件登录过程 在medium.com上,获取电子邮件地址(无密码)并发送登录信息 链接< /P>

会话令牌必须一次性使用,并且有一分钟的固定到期时间。

# this token will log in as the given user for the entire session -# NB use with caution.token=RequestToken.objects.create_token(scope="foo",login_mode=RequestToken.LOGIN_MODE_SESSION,user=User.objects.get(username="hugo"))

实施

该项目包含中间件和一个视图函数装饰器 验证添加到站点URL的请求令牌。

request_token.models.requesttoken -存储令牌详细信息

步骤1是创建一个requestToken 用于修改其行为和强制属性- 范围 。这是一个 文本值-可以是您喜欢的任何内容-它由函数decorator使用 (如下所述)确认给定的令牌与 已调用-即 标记.scope 必须与函数装饰器scope kwarg:

token=RequestToken(scope="foo")# this will raise a 403 without even calling the function@use_request_token(scope="bar")defincorrect_scope(request):pass# this will call the function as expected@use_request_token(scope="foo")defcorrect_scope(request):pass

令牌本身-必须作为querystring附加到链接的值 参数-是一个jwt-来自 requestToken.jwt() 方法。例如, 如果您发送电子邮件,则可以将电子邮件呈现为HTML模板 像这样:

{% if token %}
    <ahref="{{url}}?rt={{token.jwt}}>click here</a>
{% else %}
    <a href="{{url}}">click here</a>
{% endif %}

如果您在jwt.io网站上找到更多信息之前还没有遇到jwt。生成的令牌将包括以下jwt声明(可用作属性requesttoken.claims:

  • max :令牌可使用的最大次数
  • sub :范围
  • mod :登录模式
  • jti :令牌id
  • aud :(可选)令牌所代表的用户
  • exp :(可选)令牌的过期时间
  • iat :(可选)颁发令牌的时间
  • ndf :(可选)令牌的非早于时间

请求令牌.中间件.请求令牌中间件 -解码并验证令牌

requestTokenMiddleware 将查找一个QueryString令牌值(参数名默认为"rt",可以使用 jwt_queryString_arg 设置重写),如果找到一个,它将验证该令牌(使用jwt decode验证)。如果令牌被验证,它将从数据库中获取令牌对象,并对令牌属性执行附加验证。如果令牌签出,它将作为 令牌 属性添加到传入请求中。这样,您可以将任意数据(存储在令牌上)添加到传入请求。

如果令牌指定了用户,则将 请求.user 更新为 反映这一点。中间件必须在django auth中间件之后运行,并且 在任何检查/monkey的自定义中间件修补 request.user

如果无法验证令牌,则返回403。

请求令牌。装饰器。使用请求令牌 -将令牌权限应用于视图

一种函数装饰器,它接受一个强制的kwargs( 作用域 )和一个可选的kwargs 千瓦( 必需的 )。 作用域用于将标记与视图函数匹配- 它只是一个直接的文本匹配-值可以是任何你喜欢的,但是如果 标记作用域是"foo",则相应的视图函数decorator作用域必须 比赛。所需的 Kwarg用于指示视图是否必须 为了使用或不使用的标记。默认为false-如果标记 如果没有,则将按原样调用视图函数。

如果作用域不匹配,则返回403。

如果required为true且未提供令牌,则返回a 403。

安装

使用pip下载/安装应用程序:

pip install django-request-token

将应用程序请求令牌添加到您的已安装应用程序中

# settings.pyINSTALLED_APPS=('django.contrib.admin','django.contrib.auth','django.contrib.contenttypes','django.contrib.sessions','django.contrib.messages','django.contrib.staticfiles','request_token',...)

将中间件添加到设置中, 在标准身份验证中间件之后, 在任何使用 request.user 的定制中间件之前

MIDDLEWARE_CLASSES=[# default django middleware'django.contrib.sessions.middleware.SessionMiddleware','django.middleware.common.CommonMiddleware','django.middleware.csrf.CsrfViewMiddleware','django.contrib.auth.middleware.AuthenticationMiddleware','django.contrib.messages.middleware.MessageMiddleware','request_token.middleware.RequestTokenMiddleware',]

现在可以通过shell(或在 或者通过管理界面。一旦您添加了 requestToken 可以将标记jwt添加到您的url中(使用 jwt() 方法):

>>>token=RequestToken.objects.create_token(scope="foo")>>>url="https://example.com/foo?rt="+token.jwt()

您现在有一个启用了请求令牌的url。您可以使用此令牌保护 使用视图装饰器查看函数:

# a token that can be used to access a public url, without authenticating# as a user, but carrying a payload (affiliate_id).token=RequestToken.objects.create_token(scope="foo",login_mode=RequestToken.LOGIN_MODE_NONE,data={'affiliate_id':1})...@use_request_token(scope="foo")functionview_func(request):# extract the affiliate id from an token _if_ one is suppliedaffiliate_id=(request.token.data['affiliate_id']ifhasattr(request,'token')elseNone)
0

nb decorator的"scope"参数用于将函数绑定到 传入令牌-如果有人试图在另一个URL上使用有效令牌,则 将返回403。

nb当前仅支持视图功能-不支持基于类的视图。

设置

从环境或django设置中读取设置:

# a token that can be used to access a public url, without authenticating# as a user, but carrying a payload (affiliate_id).token=RequestToken.objects.create_token(scope="foo",login_mode=RequestToken.LOGIN_MODE_NONE,data={'affiliate_id':1})...@use_request_token(scope="foo")functionview_func(request):# extract the affiliate id from an token _if_ one is suppliedaffiliate_id=(request.token.data['affiliate_id']ifhasattr(request,'token')elseNone)
1
  • 请求令牌查询字符串

querystring参数名,用于从传入的 请求,默认为 rt

  • 请求令牌有效期

会话令牌具有以分钟为单位指定的默认到期时间间隔。 主用例(上面)规定到期时间不应该再是 接收和打开电子邮件所需的时间,默认为 10 (分钟)。

  • 请求令牌模板

指定403模板以便对403响应进行预分类, 在生产中,设置如下:

# a token that can be used to access a public url, without authenticating# as a user, but carrying a payload (affiliate_id).token=RequestToken.objects.create_token(scope="foo",login_mode=RequestToken.LOGIN_MODE_NONE,data={'affiliate_id':1})...@use_request_token(scope="foo")functionview_func(request):# extract the affiliate id from an token _if_ one is suppliedaffiliate_id=(request.token.data['affiliate_id']ifhasattr(request,'token')elseNone)
2
  • 请求令牌日志令牌错误

如果装饰器或中间件引发了invalidtokenerror,则 将记录为 requestTokenErrorLog 对象。这使得调试 更容易,这在生产中非常重要 一个象征性的问题是一个愤怒的客户说"我的链接不起作用"。存在 能够从管理站点诊断问题是有用的,但是如果卷 或者错误是一个问题,可以通过将此值设置为任意值来禁用 不是"真"或"1"。

日志记录

调试中间件和装饰器可能很复杂,因此项目很冗长 在它的日志中(按设计)。如果你觉得它提供了太多的日志,你 可以通过设置 请求令牌的标准django日志来调整它。

通过使用 设置请求令牌日志令牌错误

测试

有一组毒性试验。

许可证

麻省理工学院< /P>

贡献

这一点也不完整,但是,它足够好,有价值,因此释放它。 如果您想为项目做出贡献,通常的github规则适用:

  1. 将回购交给你自己的账户
  2. 提交拉取请求
  3. 为任何新代码添加测试
  4. 遵循现有项目的编码方式

致谢

@jpadilla用于 pyjwt

欢迎加入QQ群-->: 979659372 Python中文网_新手群

推荐PyPI第三方库


热门话题
JavaSpring重定向请求处理程序   SwingJava:拆分字符串并将其放入文本区域的   Java:标记“”上出现语法错误,此标记后面应为表达式   web服务Java RestService从日志文件写入和读取数据   java如何将ArrayList<String>转换为char数组,然后向后打印每个单词?   java SimpleDataFormat解析返回年终日期   加密Java aes解密bytebuffer,包括填充为空字节   java有没有办法从特定的if语句调用变量?   java从更新返回到渲染   spring GRPC Java登录测试   java为什么下面的代码不工作(StringBuffer.toString!=null)   java是一种可行的模式吗?   使用Spring集成测试的JavaOSGi片段   java jCommander为未知和未使用的值引发异常?   在imageView的editText中输入的java图像URL