Django——DRF中使用JWT

简介: JWT 是一个开放标准(RFC 7519),它定义了一种用于简洁,自包含的用于通信双方之间以 JSON 对象的形式安全传递信息的方法。
+关注继续查看

聊聊JWT

1、JWT简介

JWT 是一个开放标准(RFC 7519),它定义了一种用于简洁,自包含的用于通信双方之间以 JSON 对象的形式安全传递信息的方法。JWT 可以使用 HMAC 算法或者是 RSA 的公钥密钥对进行签名。它具备两个特点:

简洁(Compact)

可以通过URL, POST 参数或者在 HTTP header 发送,因为数据量小,传输速度快

自包含(Self-contained)

负载中包含了所有用户所需要的信息,避免了多次查询数据库

2、JWT 组成

Header 头部

头部包含了两部分,token 类型和采用的加密算法

{
  "alg": "HS256",
  "typ": "JWT"
}

typ: (Type)类型。在JOSE Header中这是个可选参数,但这里我们需要指明类型是JWT。

alg: (Algorithm)算法,必须是JWS支持的算法

它会使用 base64url编码组成 JWT 结构的第一部分

Base64URL 算法

这个算法跟 Base64 算法基本类似,是一种编码,也就是说,它是可以被翻译回原来的样子来的。它并不是一种加密过程

JWT 作为一个令牌(token),有些场合可能会放到 URL(比如 api.example.com/?token=xxx)。Base64 有三个字符+、/和=,在 URL 里面有特殊含义,所以要被替换掉:=被省略、+替换成-,/替换成_ 。这就是 Base64URL 算法。

Payload 负载

这部分就是我们存放信息的地方了,你可以把用户 ID 等信息放在这里,JWT 规范里面对这部分有进行了比较详细的介绍,JWT 规定了7个官方字段,供选用

iss (issuer):签发人
exp (expiration time):过期时间
sub (subject):主题
aud (audience):受众
nbf (Not Before):生效时间
iat (Issued At):签发时间
jti (JWT ID):编号

常用的有,

{
    "iss": "lee JWT",
    "iat": 1441593502,
    "exp": 1441594722,
    "aud": "www.example.com",
    "sub": "123456@qq.com"
    }

同样的,它会使用 base64url 编码组成 JWT 结构的第二部分

Signature 签名

签名的作用是保证 JWT 没有被篡改过

前面两部分都是使用 base64url 进行编码的,即前端可以解开知道里面的信息。Signature 需要使用编码后的 header 和 payload 以及我们提供的一个密钥,这个密钥只有服务器才知道,不能泄露给用户,然后使用 header 中指定的签名算法(HS256)进行签名。

HMACSHA256(
  base64UrlEncode(header) + "." +
  base64UrlEncode(payload),
  secret)

算出签名以后,把 Header、Payload、Signature 三个部分拼成一个字符串,每个部分之间用"点"(.)分隔,就可以返回给用户。

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjU3ZmVmMTY0ZTU0YWY2NGZmYzUzZGJkNSIsInhzcmYiOiI0ZWE1YzUwOGE2NTY2ZTc2MjQwNTQzZjhmZWIwNmZkNDU3Nzc3YmUzOTU0OWM0MDE2NDM2YWZkYTY1ZDIzMzBlIiwiaWF0IjoxNDc2NDI3OTMzfQ.PA3QjeyZSUh7H0GfE0vJaKW4LjKJuC3dVLQiY4hii8s

签名的目的:

 最后一步签名的过程,实际上是对头部以及负载内容进行签名,防止内容被窜改。如果有人对头部以及负载的内容解码之后进行修改,再进行编码,最后加上之前的签名组合形成新的JWT的话,那么服务器端会判断出新的头部和负载形成的签名和JWT附带上的签名是不一样的。如果要对新的头部和负载进行签名,在不知道服务器加密时用的密钥的话,得出来的签名也是不一样的。

3、JWT 的使用方式

客户端收到服务器返回的 JWT,可以储存在 Cookie 里面,也可以储存在 localStorage。

此后,客户端每次与服务器通信,都要带上这个 JWT。你可以把它放在 Cookie 里面自动发送,但是这样不能跨域,所以更好的做法是放在 HTTP 请求的头信息Authorization字段里面。

首先,前端通过Web表单将自己的用户名和密码发送到后端的接口。这一过程一般是一个HTTP POST请求。建议的方式是通过SSL加密的传输(https协议),从而避免敏感信息被嗅探。

后端核对用户名和密码成功后,将用户的id等其他信息作为JWT Payload(负载),将其与头部分别进行Base64编码拼接后签名,形成一个JWT。形成的JWT就是一个形同lll.zzz.xxx的字符串。

后端将JWT字符串作为登录成功的返回结果返回给前端。前端可以将返回的结果保存在localStorage或sessionStorage上,退出登录时前端删除保存的JWT即可。

前端在每次请求时将JWT放入HTTP Header中的Authorization位。(解决XSS和XSRF问题)

后端检查是否存在,如存在验证JWT的有效性。例如,检查签名是否正确;检查Token是否过期;检查Token的接收方是否是自己(可选)。

4、JWT 的几个特点

(1)JWT 默认是不加密,但也是可以加密的。生成原始 Token 以后,可以用密钥再加密一次。

(2)JWT 不加密的情况下,不能将秘密数据写入 JWT。

(3)JWT 不仅可以用于认证,也可以用于交换信息。有效使用 JWT,可以降低服务器查询数据库的次数。

(4)JWT 的最大缺点是,由于服务器不保存 session 状态,因此无法在使用过程中废止某个 token,或者更改 token 的权限。也就是说,一旦 JWT 签发了,在到期之前就会始终有效,除非服务器部署额外的逻辑。

(5)JWT 本身包含了认证信息,一旦泄露,任何人都可以获得该令牌的所有权限。为了减少盗用,JWT 的有效期应该设置得比较短。对于一些比较重要的权限,使用时应该再次对用户进行认证。

(6)为了减少盗用,JWT 不应该使用 HTTP 协议明码传输,要使用 HTTPS 协议传输。

DRF中使用JWT

1. 安装

注意:切换到自己项目的 Python 环境中进行安装

$ pip3 install djangorestframework-jwt

2. 使用

全局设置使用

在 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',
    ),
}

设置 Tocken 有效时间和认证 token 信息的前缀

在 settings.py 文件中设置

import datetime
JWT_AUTH = {
    'JWT_REFRESH_EXPIRATION_DELTA': datetime.timedelta(days=7),

    'JWT_AUTH_HEADER_PREFIX': 'JWT',
}

INSTALLEN_APP中加入rest_framework,authtoken

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'rest_framework',
    'apps.interviewer',
    'apps.exam',
    'apps.administrator',
    'rest_framework.authtoken'
]

生成和解码token:

import jwt
encoded = jwt.encode({"some": "payload"}, "secret", algorithm="HS256")
print(encoded)
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzb21lIjoicGF5bG9hZCJ9.Joh1R2dYzkRvDkqv3sygm5YyK8Gi4ShZqbhK2gxcs2U
jwt.decode(encoded, "secret", algorithms=["HS256"])
{'some': 'payload'}

同样的问题,下一次接口登录的时候,怎么获取已经登录的用户信息呢? django 中是有中间件处理,现在使用 token 怎么办,那么也要自定义一个中间件,需要实现的功能也是和 AuthenticationMiddleware 中处理逻辑类似,它是从会话中去拿用户的信息,这里我们需要解码 token,获取用户的信息(生成token的时候可以将用户信息放进去)。

中间件中整合使用

from django.conf import settings
from django.utils.deprecation import MiddlewareMixin
from jose import jwt, ExpiredSignatureError, JWTError

from xx.models import User


class AuthMiddleware(MiddlewareMixin):
    def process_request(self, request):
        token = request.META.get('HTTP_AUTHORIZATION')
        if token:
            token = token.replace('Bearer ', '')
            try:
                jwt_token = jwt.decode(token, settings.SECRET_KEY)
            except ExpiredSignatureError:
                return False
            except JWTError:
                return False

            user = User.objects.get(id=jwt_token.get('sub'))
            request.user = user

        return


目录
相关文章
|
9天前
|
Python
django auth模块使用jwt进行登录不能更新last_login!
今天使用django自带的用户系统,进行jwt,重写了user模型,使用手机登录,于是就想用django自带的登录验证... 哎,一切折腾都在于不熟悉
|
9天前
|
API Python
Django实现jwt方式登录
jwt的概念这边就不再阐述了,就是cookie的替代品 view.py
|
2月前
|
JSON 算法 安全
Django JWT验证
Django JWT验证
102 0
|
4月前
|
JavaScript 前端开发 应用服务中间件
Linux--部署Django+DRF+vue项目
Linux--部署Django+DRF+vue项目
|
4月前
|
JSON 安全 数据安全/隐私保护
Django之JWT库与SimpleJWT库的使用
使用Django框架时,可以选择jwt或simplejwt来增强其功能。这两个扩展提供了与JWT认证相关的功能,可以帮助实现安全而高效的用户认证和授权机制。通过使用它们,可以轻松地将JWT集成到Django应用程序中,并提供可靠的用户身份验证和权限管理功能。
75 1
|
7月前
|
Python
django drf 常用命令和常见问题
django drf 常用命令和常见问题
|
7月前
|
数据库 Python
django drf 实现只有超级用户才能注册账号(涉及自定义权限permissions,获取token信息解析token信息)
django drf 实现只有超级用户才能注册账号(涉及自定义权限permissions,获取token信息解析token信息)
|
7月前
|
API Python
django drf基于rest_framework_simplejwt实现登录获取token、检验token,token使用
django drf基于rest_framework_simplejwt实现登录获取token、检验token,token使用
|
7月前
|
JSON 数据格式 Python
django drf 案例--实现url编码和json和dict格式转化小工具(涉及定义模型类,序列化器,类视图,路由),接口测试
django drf 案例--实现url编码和json和dict格式转化小工具(涉及定义模型类,序列化器,类视图,路由),接口测试
|
7月前
|
SQL 关系型数据库 MySQL
django drf 初始化配置(mysql、跨域访问、默认用户模型)和用户模型重写,数据迁移,解决用户模型重写后无法创建超级用户的问题
django drf 初始化配置(mysql、跨域访问、默认用户模型)和用户模型重写,数据迁移,解决用户模型重写后无法创建超级用户的问题
相关产品
云迁移中心
推荐文章
更多