标签:客户 userinfo ssi admin 存在 type href python 响应
? jwt : Json web token,一般被用来在身份提供者和服务提供者间传递被认证的用户身份信息,以便于从资源服务器获取资源,也可以增加一些额外的其它业务逻辑所必须的声明信息,该token也可直接被用于认证,也可被加密。
? http协议是一种无状态、短连接的协议,而这就意味着如果用户向应用提供了用户名和密码来进行用户认证,那么下一次请求时,用户还要再一次进行用户认证才行,因为根据http协议,我们并不能知道是哪个用户发出的请求,所以为了应用能识别是哪个用户发出的请求,我们只能在服务器存储一份用户登录的信息,也就是session。
这份登录信息session会在响应时传递给浏览器,保存在cookie,以便下次请求携带session,这样就能够识别请求来自哪个用户了,这就是传统的基于session认证。
? 不需要在服务端去保留用户的认证信息或者会话信息。这就意味着基于token认证机制的应用不需要去考虑用户在哪一台服务器登录了,这就有了扩展性、安全性。
流程:
? token必须要在每次请求时传递给服务端,它应该保存在请求头里, 另外,服务端要支持CORS(跨来源资源共享)
策略,一般我们在服务端这么做就可以了Access-Control-Allow-Origin: *
。
? JWT是由三段信息构成的,将这三段信息文本用.链接一起就构成了Jwt字符串。
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ
结构:
header: {'typ':'JWT',"alg":'HS256'}
payload: {"user_id":1, 'username':'xx', 'exp':'超时时间'}
signature: 前两部分加密后拼接,在加密
头部header:{‘typ‘:‘JWT‘,"alg":‘HS256‘}
然后将头部进行base64ulr加密,构成第一部分
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
载荷payload: {"user_id":1, ‘username‘:‘xx‘, ‘exp‘:‘超时时间‘} 存放一些有效的信息,不建议有敏感的信息。
标准中注册声明(不强制):
iss: jwt签发者
sub: jwt所面向的用户
aud: 接收jwt的一方
exp: jwt的过期时间,这个过期时间必须要大于签发时间
nbf: 定义在什么时间之前,该jwt都是不可用的.
iat: jwt的签发时间
jti: jwt的唯一身份标识,主要用来作为一次性token,从而回避重放攻击
公共声明
一般添加用户的相关信息或其他业务需要的必要信息。
这部分也会进行base64url加密,构成第二部分,例如:
eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9
签名signature:
这部分会将上面两部分加密后得到的字符串用.
拼接,然后先进行hs256加密、加盐,再进行base64url加密,组成第三部分,例如:
TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ
然后将上面上部分用.
连接,就组成了最终的token。
当用户认证成功后,就会给浏览器返回一个token字符串,服务端不保存,下次再来请求时,会携带着token
优点:
缺点:
安装
pip3 install djangorestframework-jwt
setting.py
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'api.apps.ApiConfig',
'rest_framework',
'rest_framework_jwt' # 注册
]
# JWT过期时间设置
JWT_AUTH = {
'JWT_EXPIRATION_DELTA': datetime.timedelta(minutes=10), # 10分钟过期
}
用户登录
import uuid
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.versioning import URLPathVersioning
from rest_framework import status
from rest_framework_jwt.settings import api_settings
from api import models
class LoginView(APIView):
"""
登录接口
"""
def post(self,request,*args,**kwargs):
# 基于jwt的认证
# 1.去数据库获取用户信息
jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER
user = models.UserInfo.objects.filter(**request.data).first()
if not user:
return Response({'code':1000,'error':'用户名或密码错误'})
payload = jwt_payload_handler(user) # 产生第二段的字典类型{'user_id':1, 'username':xxx, 'exp':当前时间+过期时间段}
token = jwt_encode_handler(payload) # 加密生成jwt的token(加密、拼接全做)
return Response({'code':1001,'data':token})
用户认证
from rest_framework.views import APIView
from rest_framework.response import Response
# from rest_framework.throttling import AnonRateThrottle,BaseThrottle
import jwt
from rest_framework import exceptions
from rest_framework_jwt.settings import api_settings
class ArticleView(APIView):
# throttle_classes = [AnonRateThrottle,]
def get(self,request,*args,**kwargs):
# 获取用户提交的token,进行一步一步校验
jwt_decode_handler = api_settings.JWT_DECODE_HANDLER
jwt_value = request.query_params.get('token')
try:
payload = jwt_decode_handler(jwt_value) # 校验
except jwt.ExpiredSignature:
msg = '签名已过期'
raise exceptions.AuthenticationFailed(msg)
except jwt.DecodeError:
msg = '认证失败'
raise exceptions.AuthenticationFailed(msg)
except jwt.InvalidTokenError:
raise exceptions.AuthenpythonticationFailed()
print(payload) # 检验后的第二段数据
return Response('文章列表')
标签:客户 userinfo ssi admin 存在 type href python 响应
原文地址:https://www.cnblogs.com/yzm1017/p/11963336.html