[翻译] REST framework JWT Auth

JWT认证的REST框架

原文链接

概述

这个包提供对Django REST frameworkJSON Web Token 认证支持。

需要满足条件

  • Python (2.7, 3.3, 3.4, 3.5)
  • Django (1.8, 1.9, 1.10)
  • Django REST Framework (3.0, 3.1, 3.2, 3.3, 3.4, 3.5)

安全

与JWT的一些更典型的用法不同,此模块仅生成身份验证令牌,该身份验证令牌将验证请求DRF保护的API资源之一的用户。实际的请求参数本身不包含在JWT声明中,这意味着它们没有被签名并且可能被篡改。 您仅应通过SSL / TLS公开API端点,以防止内容篡改和某些类型的重放攻击。

安装

使用pip方式安装

$ pip install djangorestframework-jwt

用法

settings.py中,添加JSONWebTokenAuthentication到Django rest framework的DEFAULT_AUTHENTICATION_CLASSES中。

REST_FRAMEWORK = {
    'DEFAULT_PERMISSION_CLASSES': (
        'rest_framework.permissions.IsAuthenticated',
    ),
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework_jwt.authentication.JSONWebTokenAuthentication',
        'rest_framework.authentication.SessionAuthentication',
        'rest_framework.authentication.BasicAuthentication',
    ),
}

urls.py中,添加以下URL路由,以允许通过包含用户名和密码的POST获得令牌。

from rest_framework_jwt.views import obtain_jwt_token
#...

urlpatterns = [
    '',
    # ...

    url(r'^api-token-auth/', obtain_jwt_token),
]

如果您拥有一个用户名为admin和密码为password123的用户,则可以通过在终端中执行以下操作来简单测试端点是否正常运行。

$ curl -X POST -d "username=admin&password=password123" http://localhost:8000/api-token-auth/

或者,您可以使用Django REST框架支持的所有内容类型来获取auth令牌。 例如:

$ curl -X POST -H "Content-Type: application/json" -d '{"username":"admin","password":"password123"}' http://localhost:8000/api-token-auth/

您是不是要找: Now in order to access protected api urls you must include the Authorization: JWT <your token> header.

现在,为了访问受保护的api网址,您必须包含Authorization:JWT <your_token>标头。

$ curl -H "Authorization: JWT <your_token>" http://localhost:8000/protected-url/

刷新令牌

如果JWT_ALLOW_REFRESH为True,则可以“刷新”未过期的令牌以获得具有更新的过期时间的全新令牌。 添加如下网址格式:

from rest_framework_jwt.views import refresh_jwt_token
#  ...

urlpatterns = [
    #  ...
    url(r'^api-token-refresh/', refresh_jwt_token),
]

如下所示将现有令牌传递到刷新端点:{“ token”:EXISTING_TOKEN}。 请注意,只有未过期的令牌才有效。 JSON响应看起来与正常的获取令牌端点{“ token”:NEW_TOKEN}相同。

$ curl -X POST -H "Content-Type: application/json" -d '{"token":"<EXISTING_TOKEN>"}' http://localhost:8000/api-token-refresh/

可以重复使用令牌刷新(令牌1->令牌2->令牌3),但是此令牌链将原始令牌(使用用户名/密码凭证获取)的时间存储为orig_iat。 您最多只能将令牌刷新到JWT_REFRESH_EXPIRATION_DELTA

一个典型的用例是一个Web应用程序,您想让用户“登录”该网站而不必重新输入密码,或者在令牌过期之前被吓倒了。 想象一下,他们有一个1个小时的令牌,正好在他们仍在做某事的最后一刻。 使用移动设备,您也许可以存储用户名/密码来获取新令牌,但这在浏览器中并不是一个好主意。 每次用户加载页面时,您都可以检查是否存在现有的未过期令牌,如果该令牌即将过期,请刷新该令牌以扩展会话。 换句话说,如果用户正在活跃地使用您的网站,则他们可以保持其“会话(session)”有效。

验证令牌

在某些微服务架构中,身份验证由单个服务处理。 其他服务委托确认用户已登录到此身份验证服务的责任。 这通常意味着服务会将将从用户收到的JWT传递给身份验证服务,并在将受保护资源返回给用户之前等待JWT有效的确认。

此软件包使用验证端点支持此设置。 添加以下网址格式:

from rest_framework_jwt.views import verify_jwt_token

#...

urlpatterns = [
    #  ...
    url(r'^api-token-verify/', verify_jwt_token),
]

将令牌传递到验证端点将返回200响应,如果令牌有效,则返回令牌。 否则,它将返回一个400 Bad Request(错误请求)以及一个指出令牌无效的原因的错误。

$ curl -X POST -H "Content-Type: application/json" -d '{"token":"<EXISTING_TOKEN>"}' http://localhost:8000/api-token-verify/

其它配置

JWT_AUTH = {
    'JWT_ENCODE_HANDLER':
    'rest_framework_jwt.utils.jwt_encode_handler',

    'JWT_DECODE_HANDLER':
    'rest_framework_jwt.utils.jwt_decode_handler',

    'JWT_PAYLOAD_HANDLER':
    'rest_framework_jwt.utils.jwt_payload_handler',

    'JWT_PAYLOAD_GET_USER_ID_HANDLER':
    'rest_framework_jwt.utils.jwt_get_user_id_from_payload_handler',

    'JWT_RESPONSE_PAYLOAD_HANDLER':
    'rest_framework_jwt.utils.jwt_response_payload_handler',

    'JWT_SECRET_KEY': settings.SECRET_KEY,
    'JWT_GET_USER_SECRET_KEY': None,
    'JWT_PUBLIC_KEY': None,
    'JWT_PRIVATE_KEY': None,
    'JWT_ALGORITHM': 'HS256',
    'JWT_VERIFY': True,
    'JWT_VERIFY_EXPIRATION': True,
    'JWT_LEEWAY': 0,
    'JWT_EXPIRATION_DELTA': datetime.timedelta(seconds=300),
    'JWT_AUDIENCE': None,
    'JWT_ISSUER': None,

    'JWT_ALLOW_REFRESH': False,
    'JWT_REFRESH_EXPIRATION_DELTA': datetime.timedelta(days=7),

    'JWT_AUTH_HEADER_PREFIX': 'JWT',
    'JWT_AUTH_COOKIE': None,

}

该软件包使用JSON Web令牌Python实现PyJWT,并允许修改其中的一些可用选项。

JWT_SECRET_KEY

这是用于签署JWT的密钥。确保这是安全的,并且不会共享或公开。
默认值为项目的settings.SECRET_KEY

JWT_GET_USER_SECRET_KEY

这是JWT_SECRET_KEY的更强大的版本。它是按用户定义的,因此,如果令牌被盗用,所有者可以轻松更改它。更改此值将使给定用户的所有令牌不可用。值应该是一个函数,仅接受用户作为参数并返回它的密钥。
默认为None

JWT_PUBLIC_KEY

这是cryptography.hazmat.primitives.asymmetric.rsa.RSAPublicKey类型的对象。它将用于验证传入的JWT的签名。设置后将覆盖JWT_SECRET_KEY阅读文档以获取更多详细信息。请注意,必须将JWT_ALGORITHM设置为RS256RS384RS512之一。
默认为None

JWT_PRIVATE_KEY

这是cryptography.hazmat.primitives.asymmetric.rsa.RSAPrivateKey类型的对象。它将用于对JWT的签名组件进行签名。设置后将覆盖JWT_SECRET_KEY阅读文档以获取更多详细信息。请注意,必须将JWT_ALGORITHM设置为RS256RS384RS512之一。
默认为None

JWT_ALGORITHM

可能的值是PyJWT中任何受支持的密码签名算法
默认值为“ HS256”

JWT_VERIFY

如果密码错误,则会引发一个jwt.DecodeError告诉您。您仍然可以通过将JWT_VERIFY设置为False来获得有效负载。
默认值为True

JWT_VERIFY_EXPIRATION

您可以通过将JWT_VERIFY_EXPIRATION设置为False来关闭到期时间验证。如果没有到期验证,JWT将永远存在,这意味着攻击者可以无限期地使用泄露的令牌。
默认值为True

JWT_LEEWAY

这使您可以验证过去但不是很远的到期时间。例如,如果您有一个JWT有效负载,其有效时间设置为创建后的30秒,但您知道有时您将在30秒后对其进行处理,则可以将回旋时间设置为10秒,以便有一定的余量。
默认值为0秒。

JWT_EXPIRATION_DELTA

这是Python的datetime.timedelta的一个实例。这将被添加到datetime.utcnow()来设置到期时间。
默认值为datetime.timedelta(seconds = 300)(5分钟)

JWT_AUDIENCE

这是一个字符串,将根据令牌的aud字段(如果存在)进行检查。
默认值为None(如果JWT上出现aud,则失败)。

JWT_ISSUER

这是一个字符串,将根据令牌的iss字段进行检查。
默认值为None(不检查JWT上的iss)。

JWT_ALLOW_REFRESH

启用令牌刷新功能。从rest_framework_jwt.views.obtain_jwt_token发行的令牌将具有orig_iat字段。默认为False

JWT_REFRESH_EXPIRATION_DELTA

令牌刷新的限制是一个datetime.timedelta实例。这是原始令牌之后可以刷新未来令牌的时间。
默认值为datetime.timedelta(days = 7)(7天)

JWT_PAYLOAD_HANDLER

指定自定义函数以生成令牌有效载荷。

JWT_PAYLOAD_GET_USER_ID_HANDLER

如果您存储的user_id与默认的有效负载处理程序不同,请实现此功能以从有效负载中获取user_id。注意:不推荐使用JWT_PAYLOAD_GET_USERNAME_HANDLER

JWT_PAYLOAD_GET_USERNAME_HANDLER

如果您存储的username与默认有效负载处理程序不同,请实施此功能以从有效负载中获取用户名。

JWT_RESPONSE_PAYLOAD_HANDLER

负责控制登录或刷新后返回的响应数据。重写以返回自定义响应,例如包括用户的序列化表示形式。默认返回JWT令牌。

def jwt_response_payload_handler(token, user=None, request=None):
    return {
        'token': token,
        'user': UserSerializer(user, context={'request': request}).data
    }

默认是 {'token': token}

JWT_AUTH_HEADER_PREFIX

您可以修改需要与令牌一起发送的Authorization标头值前缀。 默认值为JWT。 PR#4中引入了此决定,以允许在DRF中同时使用此程序包和OAuth2。

用于令牌和授权标头的另一个常见值是Bearer

默认值为JWT

JWT_AUTH_COOKIE

如果除了授权标头之外还想使用http cookie作为令牌的有效传输方式,则可以将其设置为字符串。 您在此处设置的字符串将用作在请求令牌时将在响应标头中设置的cookie名称。 令牌验证过程还将调查此cookie(如果已设置)。 如果请求中同时包含标头和cookie,则“授权”标头具有优先权。

默认值为“None”,创建令牌时不设置cookie,或在验证令牌时不接受。

扩展JSONWebTokenAuthentication

现在,JSONWebTokenAuthentication假定JWT将出现在标头或cookie(如果已配置)中(请参阅JWT_AUTH_COOKIE)。 JWT规范不需要这样做(请参阅:进行服务调用)。 例如,JWT可以出现在查询字符串中。 如果用户无法设置标头(例如HTML中的src元素),则需要具有在查询字符串中发送JWT的功能。

为了实现此功能,用户可以编写自定义身份验证

class JSONWebTokenAuthenticationQS(BaseJSONWebTokenAuthentication):
    def get_jwt_value(self, request):
         return request.QUERY_PARAMS.get('jwt')

建议使用BaseJSONWebTokenAuthentication,这是一个新的基类,没有解析HTTP标头的逻辑。

手动创建新令牌

有时您可能需要手动生成令牌,例如在创建帐户后立即将令牌返回给用户。 您可以按照以下步骤进行操作:

from rest_framework_jwt.settings import api_settings

jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER

payload = jwt_payload_handler(user)
token = jwt_encode_handler(payload)
本作品采用《CC 协议》,转载必须注明作者和本文链接
Stay hungry, stay foolish.
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!