Python Django DRF框架JWT Auth

REST框架JWT Auth

Django REST Framework的JSON Web令牌认证支持

概观
该软件包为Django REST框架提供JSON Web令牌认证支持。

要求
Python(2.7,3.3,3.4,3.5)
Django(1.8,1.9,1.10)
Django REST框架(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框架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框架支持的所有内容类型来获取身份验证令牌。例如:

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

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

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

刷新令牌
如果JWT_ALLOW_REFRESH为True,则可以“刷新” 未过期的令牌以获得具有更新到期时间的全新令牌。像这样添加一个URL模式:

 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小时的令牌,只是在他们还在做某事的最后一刻。使用移动设备,您可以存储用户名/密码以获取新令牌,但这在浏览器中不是一个好主意。每次用户加载页面时,您都可以检查是否存在现有的未过期令牌,如果它已接近过期,请刷新它以扩展其会话。换句话说,如果用户正在积极使用您的网站,他们可以保持他们的“会话”活着。

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

使用验证端点在此包中支持此设置。添加以下URL模式:

 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/

其他设置
您可以覆盖一些其他设置,类似于您使用Django REST框架本身的方式。以下是所有可用的默认值。

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 Token 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必须设置为一个RS256,RS384或RS512。

默认是None。

JWT_PRIVATE_KEY
这是一个类型的对象cryptography.hazmat.primitives.asymmetric.rsa.RSAPrivateKey。它将用于签署JWT的签名组件。JWT_SECRET_KEY设置时将覆盖。阅读文档以获取更多详细信息。请注意,JWT_ALGORITHM必须设置为一个RS256,RS384或RS512。

默认是None。

JWT_ALGORITHM
可能的值是PyJWT中用于加密签名的任何支持算法。

默认是"HS256"。

JWT_VERIFY
如果秘密是错误的,它会引发一个jwt.DecodeError,告诉你这样。您仍然可以通过设置JWT_VERIFYto来获取有效负载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(如果aud在JWT上存在则失败)。

JWT_ISSUER
这是一个字符串,将根据iss令牌字段进行检查。

默认是None(不要检查issJWT)。

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方式与默认的有效负载处理程序不同,请实现此功能以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
如果除了Authorization标头之外还要使用http cookie作为令牌的有效传输,则可以将其设置为字符串。您在此处设置的字符串将用作cookie名称,该名称将在请求令牌时在响应标头中设置。如果设置,令牌验证程序也将查看此cookie。如果请求中存在标头和cookie,则“授权”标头优先。

默认为None且在创建令牌时未设置cookie,也未在验证时接受。

扩展 JSONWebTokenAuthentication
现在JSONWebTokenAuthentication假设JWT将在标题中,或者如果配置了cookie(请参阅JWT_AUTH_COOKIE)。JWT规范不要求这样做(参见:拨打服务电话)。例如,JWT可能会出现在查询字符串中。在用户无法设置标题的情况下(例如HTML中的src元素),需要在查询字符串中发送JWT的能力。

要实现此功能,用户可以编写自定义Authentication:

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)

猜你喜欢

转载自blog.csdn.net/Mr_w_ang/article/details/83387334