django jwt认证
jwt组成
import base64, json, hashlib
if __name__ == '__main__':
"""jwt 头部的生成"""
header_data = {"typ": "jwt", "alg": "HS256"}
header = base64.b64encode( json.dumps(header_data).encode() ).decode()
print(header)
"""jwt 载荷的生成"""
payload_data = {
"sub": "root",
"exp": "150123455",#过期时间
"iat": "150103455",#签发时间
"name": "wxm",#用户名
"admin": True,
"acc_pwd": "QiLCJhbGciOiJIUzI1NiJ9QiLCJhbGciOiJIUzI1NiJ9QiLCJhbGciOiJIUzI1NiJ9",
}
# 将其进行base64编码,得到JWT的第二部分。
payload = base64.b64encode(json.dumps(payload_data).encode()).decode()
print(payload)
# from django.conf import settings
# secret = settings.SECRET_KEY
secret = 'django-insecure-hbcv-y9ux0&8qhtkgmh1skvw#v7ru%t(z-#chw#9g5x1r3z=$p'
data = header + payload + secret # 秘钥绝对不能提供给客户端。
HS256 = hashlib.sha256()
HS256.update(data.encode('utf-8'))
signature = HS256.hexdigest()
print(signature)
# jwt 最终的生成
token = f"{header}.{payload}.{signature}"
print(token)
jwt认证流程:
- 客服端输入用户名和密码请求登录,获取token
- 客服端通过token访问后端,后端验证token,即通过jwt头部和载荷信息,加密校验signature,从而保证数据不被篡改
- 数据未篡改,校验是否过期,校验通过,返回数据
djangorestframework集成jwt功能
安装:
pip install djangorestframework-jwt
settings配置项:
# drf配置
REST_FRAMEWORK = {
# 自定义认证
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework_jwt.authentication.JSONWebTokenAuthentication', # jwt认证
),
}
import datetime
# jwt认证相关配置项
JWT_AUTH = {
# 设置jwt的有效期
'JWT_EXPIRATION_DELTA': datetime.timedelta(weeks=1), # 一周有效,
}
使用jwt模块默认提供的登录视图:
from django.urls import path
from rest_framework_jwt.views import obtain_jwt_token
from . import views
urlpatterns = [
path("login/", obtain_jwt_token, name="login"),
]
深入了解
先看下Django REST framework提供手动签发的方法,参考链接:https://jpadilla.github.io/django-rest-framework-jwt/#creating-a-new-token-manually
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)# token拿到后,可以自己定义返回数据格式,默认提供的接口返回格式不满足使用的情况
自定义载荷,解决默认信息缺失情况
from rest_framework_jwt.utils import jwt_payload_handler as payload_handler
def jwt_payload_handler(user):
"""
自定义载荷信息
:params user 用户模型实例对象
"""
# 先让jwt模块生成自己的载荷信息
payload = payload_handler(user)
# 追加自己要返回的内容
if hasattr(user, 'avatar'):
payload['avatar'] = user.avatar.url if user.avatar else ""
if hasattr(user, 'nickname'):
payload['nickname'] = user.nickname
if hasattr(user, 'money'):
payload['money'] = float(user.money)
if hasattr(user, 'credit'):
payload['credit'] = user.credit
return payload
自定义载荷后,进行配置:
import datetime
# jwt认证相关配置项
JWT_AUTH = {
# 设置jwt的有效期
# 如果内部站点,例如:运维开发系统,OA,往往配置的access_token有效期基本就是15分钟,30分钟,1~2个小时
'JWT_EXPIRATION_DELTA': datetime.timedelta(weeks=1), # 一周有效,
# 自定义载荷
'JWT_PAYLOAD_HANDLER': 'utils.authenticate.jwt_payload_handler',
}
多条件登录,jwt扩展登录视图默认调用django认证系统提供的authenticate,我们可以自定义一个认证类:
from rest_framework_jwt.utils import jwt_payload_handler as payload_handler
from django.contrib.auth.backends import ModelBackend, UserModel
from django.db.models import Q
def jwt_payload_handler(user):
"""
自定义载荷信息
:params user 用户模型实例对象
"""
# 先让jwt模块生成自己的载荷信息
payload = payload_handler(user)
# 追加自己要返回的字段内容
if hasattr(user, 'avatar'):
payload['avatar'] = user.avatar.url if user.avatar else ""
if hasattr(user, 'nickname'):
payload['nickname'] = user.nickname
if hasattr(user, 'money'):
payload['money'] = float(user.money)
if hasattr(user, 'credit'):
payload['credit'] = user.credit
return payload
def get_user_by_account(account):
"""
根据帐号信息获取user模型实例对象
:param account: 账号信息,可以是用户名,也可以是手机号,甚至其他的可用于识别用户身份的字段信息
:return: User对象 或者 None
"""
user = UserModel.objects.filter(Q(mobile=account) | Q(username=account) | Q(email=account)).first()
return user
class CustomAuthBackend(ModelBackend):
"""
自定义用户认证类[实现多条件登录]
"""
def authenticate(self, request, username=None, password=None, **kwargs):
"""
多条件认证方法
:param request: 本次客户端的http请求对象
:param username: 本次客户端提交的用户信息,可以是user,也可以mobile或其他唯一字段
:param password: 本次客户端提交的用户密码
:param kwargs: 额外参数
:return:
"""
if username is None:
username = kwargs.get(UserModel.USERNAME_FIELD)
if username is None or password is None:
return
# 根据用户名信息useranme获取账户信息
user = get_user_by_account(username)
if user and user.check_password(password) and self.user_can_authenticate(user):
return user
settings配置:
# django自定义认证
AUTHENTICATION_BACKENDS = ['utils.authenticate.CustomAuthBackend', ]
拿到token如何进行认证登录,前面我们配置的jwt认证类rest_framework_jwt.authentication.JSONWebTokenAuthentication,我们看下获取token方法远嘛如下:
def get_jwt_value(self, request):
auth = get_authorization_header(request).split()
auth_header_prefix = api_settings.JWT_AUTH_HEADER_PREFIX.lower()# 配置默认JWT
if not auth:
if api_settings.JWT_AUTH_COOKIE:
return request.COOKIES.get(api_settings.JWT_AUTH_COOKIE)
return None
if smart_text(auth[0].lower()) != auth_header_prefix:
return None
if len(auth) == 1:
msg = _('Invalid Authorization header. No credentials provided.')
raise exceptions.AuthenticationFailed(msg)
elif len(auth) > 2:
msg = _('Invalid Authorization header. Credentials string '
'should not contain spaces.')
raise exceptions.AuthenticationFailed(msg)
return auth[1]
def get_authorization_header(request):
"""
Return request's 'Authorization:' header, as a bytestring.
Hide some test client ickyness where the header can be unicode.
"""
auth = request.META.get('HTTP_AUTHORIZATION', b'') #django会默认在请求头前加HTTP并转为大写
if isinstance(auth, str):
# Work around django test client oddness
auth = auth.encode(HTTP_HEADER_ENCODING)
return auth
最后推断出请求认证时,需要AUTHORIZATION请求头,请求内容为'jwt ${jwt_token}'
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架