JWT(JSON Web Token)认证在Django前后端分离项目中的使用

2023-12-0810:30:08后端程序开发Comments1,180 views字数 7179阅读模式

什么是JWT文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/57900.html

JSON Web Token(缩写 JWT)是目前最流行的跨域认证解决方案。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/57900.html

JWT(JSON Web Token)认证在Django前后端分离项目中的使用文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/57900.html

JWT认证流程文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/57900.html

  1.     用户向服务器提交用户信息
  2.     服务器验证用户的信息
  3.     服务器通过验证时,发送给用户一个Token
  4.     客户端存储Token,并在每次请求时附送上这个Token值
  5.     服务端验证Token值,并返回数据

JWT使用流程图文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/57900.html

JWT(JSON Web Token)认证在Django前后端分离项目中的使用文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/57900.html

JWT的优缺点文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/57900.html

优点:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/57900.html

  • 通用:基于json的通用性,JWT是可以进行跨语言支持的,如JAVA、Python等语言都可以使用
  • 可存储部分非敏感数据:可以在JWT的payload部分存储一些其他业务逻辑所必要的非敏感信息
  • 便于传输:JWT的构成非常简单,字节占用很小,所以它是非常便于传输的
  • 易于拓展:它不需要在服务端保存会话信息, 所以它易于应用的扩展

缺点(注意事项):文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/57900.html

  • 不应存放敏感数据:客户端可以使用Base64URL算法解密payload部分,因而安全性无法保证
  • 保护好私钥:私钥(secret)用于服务端的认证,如透露将可能导致认证失效
  • 无法废止或修改Token:由于服务器不保存状态,因此无法在使用过程中废止某个 token,或者更改 token 的权限。一旦 JWT 签发了,在到期之前就会始终有效,除非服务器部署额外的逻辑。

JWT 的三个部分依次如下:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/57900.html

      • Header(头部)
      • Payload(负载)
      • Signature(签名)

前端如何使用JWT?文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/57900.html

前端收到服务器返回的 JWT,可以储存在 Cookie 或 localStorage 中。此后,前端每次与服务器通信,都要带上这个 JWT:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/57900.html

  • [ 不推荐 ]  放在 Cookie 里面自动发送,但是这样不能跨域
  • [ 其它方法 ] 放在 Cookie 内,跨域的时候,JWT 就放在 POST 请求的数据体里面。
  • [ 推荐 ]  放在 HTTP 请求的头信息 Authorization 字段里面Authorization: Bearer <token>

Django如何使用JWT?文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/57900.html

Django 可以基于DRF(Django REST framework),使用插件Simple JWT(djangorestframework-simplejwt)快速实现JWT认证。为什么不用 django-rest-framework-jwt :该项目已停止更新,不再支持最新版的Django。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/57900.html

安装djangorestframework-simplejwt文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/57900.html

pip install djangorestframework-simplejwt

setting.py配置文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/57900.html

#1.INSTALLED_APPS在INSTALLED_APPS中添加djangorestframework_simplejwt应用程序:INSTALLED_APPS = [    # ...    'rest_framework_simplejwt',    # 下面这个app用于刷新refresh_token后,将旧的加到到blacklist时使用    'rest_framework_simplejwt.token_blacklist'    # ...]
#2.添加simplejwt到身份验证类列表中:REST_FRAMEWORK = {    ...    'DEFAULT_AUTHENTICATION_CLASSES': (        ...        'rest_framework_simplejwt.authentication.JWTAuthentication',
    )    ...}
#3.JWT配置SIMPLE_JWT = {    'ACCESS_TOKEN_LIFETIME': timedelta(minutes=5),  # Access Token的有效期    'REFRESH_TOKEN_LIFETIME': timedelta(days=7),  # Refresh Token的有效期
    # 对于大部分情况,设置以上两项就可以了,以下为默认配置项目,可根据需要进行调整
    # 是否自动刷新Refresh Token    'ROTATE_REFRESH_TOKENS': False,      # 刷新Refresh Token时是否将旧Token加入黑名单,如果设置为False,则旧的刷新令牌仍然可以用于获取新的访问令牌。需要将'rest_framework_simplejwt.token_blacklist'加入到'INSTALLED_APPS'的配置中    'BLACKLIST_AFTER_ROTATION': False,      'ALGORITHM': 'HS256',  # 加密算法    'SIGNING_KEY': settings.SECRET_KEY,  # 签名密匙,这里使用Django的SECRET_KEY
    # 如为True,则在每次使用访问令牌进行身份验证时,更新用户最后登录时间    "UPDATE_LAST_LOGIN": False,     # 用于验证JWT签名的密钥返回的内容。可以是字符串形式的密钥,也可以是一个字典。    "VERIFYING_KEY": "",    "AUDIENCE": None,# JWT中的"Audience"声明,用于指定该JWT的预期接收者。    "ISSUER": None, # JWT中的"Issuer"声明,用于指定该JWT的发行者。    "JSON_ENCODER": None, # 用于序列化JWT负载的JSON编码器。默认为Django的JSON编码器。    "JWK_URL": None, # 包含公钥的URL,用于验证JWT签名。    "LEEWAY": 0, # 允许的时钟偏差量,以秒为单位。用于在验证JWT的过期时间和生效时间时考虑时钟偏差。
    # 用于指定JWT在HTTP请求头中使用的身份验证方案。默认为"Bearer"    "AUTH_HEADER_TYPES": ("Bearer",),     # 包含JWT的HTTP请求头的名称。默认为"HTTP_AUTHORIZATION"    "AUTH_HEADER_NAME": "HTTP_AUTHORIZATION",      # 用户模型中用作用户ID的字段。默认为"id"。    "USER_ID_FIELD": "id",     # JWT负载中包含用户ID的声明。默认为"user_id"。    "USER_ID_CLAIM": "user_id",
    # 用于指定用户身份验证规则的函数或方法。默认使用Django的默认身份验证方法进行身份验证。    "USER_AUTHENTICATION_RULE": "rest_framework_simplejwt.authentication.default_user_authentication_rule",
    #  用于指定可以使用的令牌类。默认为"rest_framework_simplejwt.tokens.AccessToken"。    "AUTH_TOKEN_CLASSES": ("rest_framework_simplejwt.tokens.AccessToken",),    # JWT负载中包含令牌类型的声明。默认为"token_type"。    "TOKEN_TYPE_CLAIM": "token_type",    # 用于指定可以使用的用户模型类。默认为"rest_framework_simplejwt.models.TokenUser"。    "TOKEN_USER_CLASS": "rest_framework_simplejwt.models.TokenUser",
    # JWT负载中包含JWT ID的声明。默认为"jti"。    "JTI_CLAIM": "jti",
    # 在使用滑动令牌时,JWT负载中包含刷新令牌过期时间的声明。默认为"refresh_exp"。    "SLIDING_TOKEN_REFRESH_EXP_CLAIM": "refresh_exp",    # 滑动令牌的生命周期。默认为5分钟。    "SLIDING_TOKEN_LIFETIME": timedelta(minutes=5),    # 滑动令牌可以用于刷新的时间段。默认为1天。    "SLIDING_TOKEN_REFRESH_LIFETIME": timedelta(days=1),    # 用于生成访问令牌和刷新令牌的序列化器。    "TOKEN_OBTAIN_SERIALIZER": "rest_framework_simplejwt.serializers.TokenObtainPairSerializer",    # 用于刷新访问令牌的序列化器。默认    "TOKEN_REFRESH_SERIALIZER": "rest_framework_simplejwt.serializers.TokenRefreshSerializer",    # 用于验证令牌的序列化器。    "TOKEN_VERIFY_SERIALIZER": "rest_framework_simplejwt.serializers.TokenVerifySerializer",    # 用于列出或撤销已失效JWT的序列化器。    "TOKEN_BLACKLIST_SERIALIZER": "rest_framework_simplejwt.serializers.TokenBlacklistSerializer",    # 用于生成滑动令牌的序列化器。    "SLIDING_TOKEN_OBTAIN_SERIALIZER": "rest_framework_simplejwt.serializers.TokenObtainSlidingSerializer",    # 用于刷新滑动令牌的序列化器。    "SLIDING_TOKEN_REFRESH_SERIALIZER": "rest_framework_simplejwt.serializers.TokenRefreshSlidingSerializer",}

添加urls文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/57900.html

from rest_framework_simplejwt.views import (    TokenObtainPairView,    TokenRefreshView,    TokenVerifyView)
urlpatterns = [    ...    path('api/token/', TokenObtainPairView.as_view(), name='token_obtain_pair'),#获取token    path('api/token/refresh/', TokenRefreshView.as_view(), name='token_refresh'),#刷新token    path('api/token/verify/', TokenVerifyView.as_view(), name='token_verify'),#验证token]

使用文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/57900.html

以下为官网的示例,也可以使用postman来测试接口。要验证 Simple JWT 是否正常工作。通过curl发送请求:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/57900.html

curl \  -X POST \  -H "Content-Type: application/json" \  -d '{"username": "davidattenborough", "password": "boatymcboatface"}' \  http://localhost:8000/api/token/...{ "access":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX3BrIjoxLCJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiY29sZF9zdHVmZiI6IuKYgyIsImV4cCI6MTIzNDU2LCJqdGkiOiJmZDJmOWQ1ZTFhN2M0MmU4OTQ5MzVlMzYyYmNhOGJjYSJ9.NHlztMGER7UADHZJlxNG0WSi22a2KaYSfd1S-AuT7lU", "refresh":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX3BrIjoxLCJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImNvbGRfc3R1ZmYiOiLimIMiLCJleHAiOjIzNDU2NywianRpIjoiZGUxMmY0ZTY3MDY4NDI3ODg5ZjE1YWMyNzcwZGEwNTEifQ.aEoAYkSJjoWH1boshQAaTkf8G3yn0kapko6HFRt7Rh4"}

可以使用返回的访问令牌来证明受保护视图的身份验证:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/57900.html

curl \  -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX3BrIjoxLCJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiY29sZF9zdHVmZiI6IuKYgyIsImV4cCI6MTIzNDU2LCJqdGkiOiJmZDJmOWQ1ZTFhN2M0MmU4OTQ5MzVlMzYyYmNhOGJjYSJ9.NHlztMGER7UADHZJlxNG0WSi22a2KaYSfd1S-AuT7lU" \  http://localhost:8000/api/some-protected-view/

当此短期访问令牌过期时,可以使用长期存在的刷新令牌来获取另一个访问令牌:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/57900.html

curl \  -X POST \  -H "Content-Type: application/json" \  -d '{"refresh":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX3BrIjoxLCJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImNvbGRfc3R1ZmYiOiLimIMiLCJleHAiOjIzNDU2NywianRpIjoiZGUxMmY0ZTY3MDY4NDI3ODg5ZjE1YWMyNzcwZGEwNTEifQ.aEoAYkSJjoWH1boshQAaTkf8G3yn0kapko6HFRt7Rh4"}' \  http://localhost:8000/api/token/refresh/
...{"access":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX3BrIjoxLCJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiY29sZF9zdHVmZiI6IuKYgyIsImV4cCI6MTIzNTY3LCJqdGkiOiJjNzE4ZTVkNjgzZWQ0NTQyYTU0NWJkM2VmMGI0ZGQ0ZSJ9.ekxRxgb9OKmHkfy-zs1Ro_xs1eMLXiR17dIDBVxeT-w"}

自定义token中返回的信息文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/57900.html

1、默认的信息文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/57900.html

JWT(JSON Web Token)认证在Django前后端分离项目中的使用文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/57900.html

默认的设置中,如果对payload(有效负载)进行解码,你就会发现,它保存了一个字典的数据,包括以下信息:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/57900.html

{  "token_type": "access",  # 令牌类型  "exp": 1685341009,       # 令牌到期时间戳  "iat": 1685340709,       # 令牌生成时间戳  "jti": "561*****************03c",  # JWT ID的声明  "user_id": 1,            # django中用户对应的id}

如果需要为它添加更多的用户信息,比如用户名称,用户手机号,email等,只要是系统后台中已存储的,都可以放在payload进行返回,由前端进行解码后,就可以提取使用了。具体步骤如下:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/57900.html

2、自定义返回信息文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/57900.html

自定义序列化器。该序列化器需继承TokenObtainPairSerializer类,可以在任意一个app中的seralizers.py中增加该自定义的序列化器,并重写了get_token()方法。在这个方法中,我们可以自定义Payload,将用户的信息添加到Token中。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/57900.html

假定为app01,则在app01/seralizers.py中增加以下代码:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/57900.html

from rest_framework_simplejwt.serializers import TokenObtainPairSerializerfrom rest_framework_simplejwt.views import TokenObtainPairView
class MyTokenObtainPairSerializer(TokenObtainPairSerializer):    @classmethod    def get_token(cls, user):        token = super().get_token(user)        # 增加想要加到token中的信息        token['username'] = user.username        token['email'] = user.email        # ...
        return token

改写simple JWT提供的默认视图,在app01/views中新增一个视图,该视图需继承至默认的视图类TokenObtainPairView文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/57900.html

from .serializers import MyTokenObtainPairSerializerfrom rest_framework_simplejwt.views import TokenObtainPairViewclass MyObtainTokenPairView(TokenObtainPairView):    serializer_class = MyTokenObtainPairSerializer  #只需修改其序列化器为刚刚自定义的即可

然后再将url中的视图改为新增加这个视图类即可。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/57900.html

参考文档:https://django-rest-framework-simplejwt.readthedocs.io/en/latest/文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/57900.html

  • 本站内容整理自互联网,仅提供信息存储空间服务,以方便学习之用。如对文章、图片、字体等版权有疑问,请在下方留言,管理员看到后,将第一时间进行处理。
  • 转载请务必保留本文链接:https://www.cainiaoxueyuan.com/bc/57900.html

Comment

匿名网友 填写信息

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定