asp.net做简易网站,百度收录效果好的网站,网络营销咨询机构,网页设计与制作的原则Django之JWT库与SimpleJWT库的使用 JWTJWT概述头部(header)载荷(payload)签名(signature) Django使用JWT说明jwt库的使用安装依赖库配置settings.py文件配置urls.py文件创建视图配置权限 SimpleJWT库的使用安装SimpleJWT库配置Django项目配置路由创建用户接口测试身份认证自定义… Django之JWT库与SimpleJWT库的使用 JWTJWT概述头部(header)载荷(payload)签名(signature) Django使用JWT说明jwt库的使用安装依赖库配置settings.py文件配置urls.py文件创建视图配置权限 SimpleJWT库的使用安装SimpleJWT库配置Django项目配置路由创建用户接口测试身份认证自定义令牌声明手动创建令牌 SimpleJWT的应用实现用户身份验证和JWT token的生成登录实现注册实现Token验证 JWT
JWT概述 JWTJSON Web Token是一种轻量级的认证和授权机制它是基于 JSON 格式的标准用于在网络应用程序或服务之间传递声明。 JWT官网https://jwt.io/
特点
无状态JWT 在服务器端不保存任何信息因此可以跨多个请求进行身份验证。自包含JWT 包含了所有必要的信息这样不需要去查询数据库或其他存储设施来验证用户身份。可扩展性由于 JWT 是基于 JSON 格式的标准因此可以很容易地扩展以添加自定义数据。强安全性JWT 使用数字签名来验证消息的完整性和真实性这样可以确保消息没有被篡改。跨域支持由于 JWT 是通过 HTTP 头部传输的因此可以轻松地在跨域场景中使用。主要应用 JWT通常用于身份验证和授权。当用户成功登录时服务器会生成一个 JWT并将其返回给客户端。客户端随后将该令牌放入每个后续请求的Authorization标头中以证明其已通过身份验证。服务器使用私钥来验证签名并从 JWT 中提取必要的信息例如用户 ID 和权限。 JWT组成
JWT由三部分组成头部、载荷和签名。
1.头部包含关于生成 JWT的算法和类型的元数据。2.载荷是JWT的主体内容它包含有关用户或其他实体的信息例如其 ID 或角色。3.签名是使用密钥对头部和载荷进行加密的字符串以确保JWT 在传输过程中不被篡改。一个JWT Token字符串由3部分组成用.隔开
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c头部(header)
JWT的头部承载两部分信息
声明类型这里是jwt声明加密的算法 通常直接使用HMAC SHA256{alg: HS256,typ: JWT
}将头部进行base64加密构成了第一部分
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9载荷(payload) 载荷就是存放有效信息的地方。有效信息包含三个部分 1.标准中注册的声明(建议但不强制使用)
iss: jwt签发者
sub: jwt所面向的用户
aud: 接收jwt的一方
exp: jwt的过期时间这个过期时间必须要大于签发时间
nbf: 定义在什么时间之前该jwt都是不可用的
iat: jwt的签发时间
jti: jwt的唯一身份标识主要用来作为一次性token,从而回避重放攻击2.公共的声明 公共的声明可以添加任何的信息一般添加用户的相关信息或其他业务需要的必要信息。但不建议添加敏感信息因为该部分在客户端可解密 3.私有的声明 私有声明是提供者和消费者所共同定义的声明一般不建议存放敏感信息因为base64是对称解密的意味着该部分信息可以归类为明文信息 {sub: 1234567890,name: John Doe,iat: 1656239122
}将其进行base64加密得到JWT的第二部分
eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ签名(signature) JWT的第三部分是一个签名信息用来防止JWT token被伪造。 签名生成过程:
1.服务器在生成jwt token时会将header和payload字符串进行拼接用.隔开2.使用一个只有服务器知道的密钥对拼接后的内容进行加密加密之后生成的字符串就是signature内容签名验证过程:
1.将客户端传递的jwt token中的header和payload字符串进行拼接用.隔开2.使用服务器自己的密钥对拼接之后的字符串进行加密3.将加密之后的内容和将客户端传递的jwt token中signature进行对比如果不一致就说明jwt token是被伪造的HMACSHA256(base64UrlEncode(header) . base64UrlEncode(payload),256-bit-secret
)注意:
不要在jwt的payload部分存放敏感信息客户端可解密得到保护好secret密钥使用https协议Django使用JWT说明 在Python项目中使用JWT生成和校验Token可以使用django-rest-framework-jwt或djangorestframework-simplejwt扩展来完成。 django-rest-framework-jwt GitHub地址https://github.com/jpadilla/django-rest-framework-jwt 文档https://jpadilla.github.io/django-rest-framework-jwt/
djangorestframework-simplejwt
GitHub地址https://github.com/jazzband/djangorestframework-simplejwt文档https://django-rest-framework-simplejwt.readthedocs.io/en/latest/
注意django-rest-framework-jwt不再维护且适合低版本框架使用若使用最新版本的Django和DRF如果使用JSON Web Token项目启动会报错
ImportError: Could not import rest_framework_jwt.authentication.JSONWebTokenAuthentication for API setting DEFAULT_AUTHENTICATION_CLASSES. ImportError: cannot import name smart_text from django.utils.encodingjwt库的使用
安装依赖库 使用pip命令安装djangorestframework-jwt库 pip install djangorestframework-jwt配置settings.py文件 添加以下内容到INSTALLED_APPS和REST_FRAMEWORK配置中 INSTALLED_APPS [...rest_framework,
]REST_FRAMEWORK {DEFAULT_AUTHENTICATION_CLASSES: (# 引入JWT认证机制当客户端将jwt token传递给服务器之后# 此认证机制会自动校验jwt token的有效性无效会直接返回401(未认证错误)rest_framework_jwt.authentication.JSONWebTokenAuthentication,rest_framework.authentication.SessionAuthentication,rest_framework.authentication.BasicAuthentication,),
}# JWT扩展配置
JWT_AUTH {# 设置生成jwt token的有效时间JWT_EXPIRATION_DELTA: datetime.timedelta(days1),
}其他可选配置项 ACCESS_TOKEN_LIFETIME: timedelta(minutes5), # 访问令牌的有效时间REFRESH_TOKEN_LIFETIME: timedelta(days1), # 刷新令牌的有效时间ROTATE_REFRESH_TOKENS: False, # 若为True则刷新后新的refresh_token有更新的有效时间BLACKLIST_AFTER_ROTATION: True, # 若为True刷新后的token将添加到黑名单中, # When True,rest_framework_simplejwt.token_blacklist,should add to INSTALLED_APPSALGORITHM: HS256, # 对称算法HS256 HS384 HS512 非对称算法RSASIGNING_KEY: SECRET_KEY,VERIFYING_KEY: None, # if signing_key, verifying_key will be ignore.AUDIENCE: None,ISSUER: None,AUTH_HEADER_TYPES: (Bearer,), # Authorization: Bearer tokenAUTH_HEADER_NAME: HTTP_AUTHORIZATION, # if HTTP_X_ACCESS_TOKEN, X_ACCESS_TOKEN: Bearer tokenUSER_ID_FIELD: id, # 使用唯一不变的数据库字段,将包含在生成的令牌中以标识用户USER_ID_CLAIM: user_id,# AUTH_TOKEN_CLASSES: (rest_framework_simplejwt.tokens.AccessToken,), # default: access# TOKEN_TYPE_CLAIM: token_type, # 用于存储令牌唯一标识符的声明名称 value:access,sliding,refresh## JTI_CLAIM: jti,## SLIDING_TOKEN_REFRESH_EXP_CLAIM: refresh_exp, # 滑动令牌是既包含到期声明又包含刷新到期声明的令牌# SLIDING_TOKEN_LIFETIME: timedelta(minutes5), # 只要滑动令牌的到期声明中的时间戳未通过就可以用来证明身份验证# SLIDING_TOKEN_REFRESH_LIFETIME: timedelta(days1), # path(token|refresh, TokenObtainSlidingView.as_view())
配置urls.py文件 配置urls.py文件添加以下路由配置 from rest_framework_jwt.views import obtain_jwt_token, refresh_jwt_token, verify_jwt_tokenurlpatterns [path(api-token-auth/, obtain_jwt_token),path(api-token-refresh/, refresh_jwt_token),path(api-token-verify/, verify_jwt_token),
]创建视图 创建自定义视图以生成JWT令牌 JWT扩展的提供了生成JWT Token的方法
from rest_framework_jwt.settings import api_settingsdata {name: Django, name: 20}
payload api_settings.JWT_PAYLOAD_HANDLER(user)
jwt_token api_settings.JWT_ENCODE_HANDLER(payload)from rest_framework_jwt.settings import api_settings# 继承JSONWebTokenAPIView使用CustomJWTSerializer进行序列化和验证
class CustomObtainJSONWebToken(JSONWebTokenAPIView):serializer_class CustomJWTSerializerclass CustomJWTSerializer(JSONWebTokenSerializer):# validate 方法对提交的用户凭据进行验证如果验证通过则生成 JWT token 并返回给客户端def validate(self, attrs):# 从请求中获取用户名和密码credentials {self.username_field: attrs.get(self.username_field),password: attrs.get(password)}# 通过 Django 自带的 authenticate 函数进行认证if all(credentials.values()):user authenticate(**credentials)if user:# 检查该用户是否处于活跃状态如果被禁用则返回错误信息if not user.is_active:raise serializers.ValidationError(User account is disabled.)# 生成JWT的payload负载payload api_settings.JWT_PAYLOAD_HANDLER(user)# 生成JWT tokenjwt_token api_settings.JWT_ENCODE_HANDLER(payload)response_data {token: jwt_token,}# 将生成的 JWT token 返回给客户端return response_dataelse:raise serializers.ValidationError(Unable to log in with provided credentials.)else:raise serializers.ValidationError(Must include {username_field} and password..format(username_fieldself.username_field))
配置权限 在视图中使用 permission_classes 装饰器指定需要验证的权限。 from rest_framework.permissions import IsAuthenticatedclass CustomView(APIView):permission_classes (IsAuthenticated,)SimpleJWT库的使用
安装SimpleJWT库
通过pip命令安装SimpleJWT库
pip install djangorestframework-simplejwt配置Django项目
在settings.py文件中添加以下配置
INSTALLED_APPS [rest_framework,rest_framework_simplejwt,
]REST_FRAMEWORK {DEFAULT_PERMISSION_CLASSES: (# 将全局权限控制方案设置为仅允许认证用户访问rest_framework.permissions.IsAuthenticated,),DEFAULT_AUTHENTICATION_CLASSES: (# JWT认证:使用SimpleJWT库提供的JWTAuthentication类来进行认证rest_framework_simplejwt.authentication.JWTAuthentication,# sesssion认证rest_framework.authentication.SessionAuthentication,# 基本认证rest_framework.authentication.BasicAuthentication,),
}
SIMPLE_JWT {# token有效时长(返回的 access 有效时长)ACCESS_TOKEN_LIFETIME: datetime.timedelta(seconds30),# token刷新的有效时间(返回的 refresh 有效时长)REFRESH_TOKEN_LIFETIME: datetime.timedelta(seconds20),
}
更多Simple JWT的配置参考: https://django-rest-framework-simplejwt.readthedocs.io/en/latest/settings.html
配置路由
配置项目级路由
from django.urls import path, include, re_pathurlpatterns [path(admin/, include((apps.admin.urls, admin), namespaceadmin)),
]配置子应用JWT视图的路由
from django.urls import include, path
from rest_framework_simplejwt.views import TokenObtainPairView, TokenRefreshView, TokenVerifyViewurlpatterns [path(login/, TokenObtainPairView.as_view(), nametoken_obtain_pair),path(refresh/, TokenRefreshView.as_view(), nametoken_refresh),path(verify/, TokenVerifyView.as_view(), nametoken_verify),
]上面视图路由使用的是使用JWT自身的类也可以自定义视图实现相关功能
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework_simplejwt.tokens import AccessToken, RefreshToken
from rest_framework.permissions import IsAuthenticatedclass TokenObtainView(APIView):# 视图需要被认证才能访问permission_classes [IsAuthenticated]def post(self, request):# 使用了SimpleJWT提供的AccessToken和RefreshToken类为认证成功的用户生成对应的JWT令牌access_token AccessToken.for_user(request.user)refresh_token RefreshToken.for_user(request.user)return Response({access_token: str(access_token),refresh_token: str(refresh_token),})from django.urls import path
from .views import TokenObtainViewurlpatterns [path(api/token/, TokenObtainView.as_view(), nametoken_obtain),
]创建用户
使用Django自带用户认证系统创建一个用户用于登录
import osfrom django.test import TestCasefrom django.contrib.auth.models import User
if not os.environ.get(DJANGO_SETTINGS_MODULE):os.environ.setdefault(DJANGO_SETTINGS_MODULE, meiduo_mall.settings)import django
django.setup()class MyTest(TestCase):User.objects.create_user(usernameadmin, passwordadmin)
接口测试
1.访问login 2.登录 登录接口返回refresh和access值
refresh用来刷新获取新的Token值access用来请求身份认证的Tokenaccess的过期时间参照配置ACCESS_TOKEN_LIFETIMErefresh的过期时间参照配置REFRESH_TOKEN_LIFETIME当用refresh刷新后access的过期时间等于当前刷新的此刻时间ACCESS_TOKEN_LIFETIME
3.Token校验 使用登录接口返回的access值调用Token校验接口 4.刷新Token
使用登录接口返回的refresh值调用Token刷新接口
当此短期访问令牌过期时可以使用长期存在的刷新令牌来获取另一个访问令牌
身份认证
使用返回的访问令牌来证明受保护视图的身份验证
path(test/, TestView.as_view(), nametest),from rest_framework.response import Response
from rest_framework.views import APIViewclass TestView(APIView):def get(self, request):return Response(tet successfully)在请求头加上Authorization格式Bearer [token值] 有空格
自定义令牌声明 自定义令牌需要视图创建一个子类并为其相应的序列化程序创建一个子类 from rest_framework_simplejwt.serializers import TokenObtainPairSerializer
from rest_framework_simplejwt.views import TokenObtainPairViewclass MyTokenObtainPairSerializer(TokenObtainPairSerializer):def validate(self, attrs):data super().validate(attrs)refresh self.get_token(self.user)data[refresh] str(refresh)data[access] str(refresh.access_token)data[username] self.user.usernamereturn dataclass MyTokenObtainPairView(TokenObtainPairView):serializer_class MyTokenObtainPairSerializer配置指向子类视图的url路由
re_path(r^login/$, views.MyTokenObtainPairView.as_view()),手动创建令牌
为用户手动创建令牌例如用户注册注册完后直接返回token
class MyCreateTokenView(APIView):permission_classes [permissions.AllowAny]def get(self, request, *args, **kwargs):return Response(Get method is not supported !)def post(self, request, *args, **kwargs):refresh RefreshToken.for_user(request.user)content {refresh: str(refresh),access: str(refresh.access_token),}return Response(content)re_path(r^register/$, views.MyCreateTokenView.as_view()),SimpleJWT的应用
实现用户身份验证和JWT token的生成
from django.contrib.auth.models import User
from django.utils import timezone
from rest_framework import serializers
from rest_framework_simplejwt.serializers import TokenObtainPairSerializer
from rest_framework_simplejwt.tokens import RefreshTokenclass AuthSerializer(TokenObtainPairSerializer):id serializers.IntegerField(label用户ID, read_onlyTrue)username serializers.CharField(label用户名)token serializers.CharField(labelToken, read_onlyTrue)refresh serializers.CharField(labelRefresh, read_onlyTrue)# 从attrs参数中获取到传入的用户名和密码def validate(self, attrs):# 获取username和passwordusername attrs[username]password attrs[password]# 进行用户名和密码校验try:user User.objects.get(usernameusername)except User.DoesNotExist:raise serializers.ValidationError(用户名或密码错误.)else:# 校验密码if not user.check_password(password):raise serializers.ValidationError(用户名或密码错误)# 给attrs中添加user属性保存登录用户attrs[user] userreturn attrsdef create(self, validated_data):# 获取登录用户useruser validated_data[user]# 设置最新登录时间user.last_login timezone.now()user.save()refresh RefreshToken.for_user(user)# 给user对象增加属性保存jwt token的数据user.refresh str(refresh)user.token str(refresh.access_token)return user登录实现 创建了AuthSerializer对象并将POST请求的参数传入进行校验。如果校验通过则调用serializer.save()方法生成JWT token并将token数据作为响应返回。 from rest_framework import status
from rest_framework.generics import CreateAPIView
from rest_framework.permissions import AllowAny
from rest_framework.response import Response
from rest_framework.views import APIViewfrom apps.zd_admin.serializers.user import AuthSerializerclass LoginView1(APIView):permission_classes [AllowAny]def post(self, request):# 获取参数并进行校验serializer AuthSerializer(datarequest.data)serializer.is_valid(raise_exceptionTrue)# 调用序列化器类的create方法,实现服务器签发jwt tokenserializer.save()return Response(serializer.data, statusstatus.HTTP_201_CREATED)class LoginView(CreateAPIView):permission_classes [AllowAny]serializer_class AuthSerializer
urlpatterns [re_path(r^login/$, views.LoginView.as_view()),
]注册实现
注册接口进行注册返回token认证信息也是同理 re_path(r^register/$, views.RegisterView.as_view()),class RegisterView(APIView):permission_classes [AllowAny]def post(self, request):user request.datausername user[username]password user[password]# 保存注册数据try:user User.objects.create_user(usernameusername, passwordpassword)except DatabaseError:raise serializers.ValidationError(注册失败)refresh RefreshToken.for_user(user)user {username: user.username, token: str(refresh.access_token), refresh: str(refresh)}return JsonResponse(user)Token验证
使用登录、注册得到的Token随着请求携带进行测试
re_path(r^test/$, views.TestView.as_view()),class TestView(APIView):def get(self, request):return Response(tet successfully)