JWT(Json Web Token):是目前最流行的跨域身份验证解决方案。
此前咱们使用的身份验证方式都是基于Session:
这种方式并无什么不妥,但其实这里有三个缺点:html
因此,咱们须要一种既能实现相同要求而且还要比session存储更有效的身份验证方式。前端
JWT经过一种加密的方式,将加密后的数据保存返回给用户本地进行保存,咱们称为token数据。其数据由三部分组成:redis
一、header声明类型和加密的算法:算法
{ 'typ': 'JWT', #固定值 'alg': 'HS256' #加密算法 }
二、payload负载
这是有效信息的存放地方,其分为三部分:标准中注册的声明、公共声明、私有声明(用户信息)
标准中的注册声明(有须要在使用,不强制使用):
iss: jwt签发者
sub: jwt所面向的用户
aud: 接收jwt的一方
exp: jwt的过时时间,这个过时时间必需要大于签发时间
nbf: 定义在什么时间以前,该jwt都是不可用的.
iat: jwt的签发时间
jti: jwt的惟一身份标识,主要用来做为一次性token,从而回避重放攻击。
公共声明:公共的声明能够添加任何的信息,通常添加用户的相关信息或其余业务须要的必要信息.
私有声明:django
{ "name": "jim", "id": "111111", "admin": true }
三、signature签名
须要base64加密后的header和base64加密后的payload使用.链接组成的字符串,而后经过header中声明的加密方式进行加盐secret组合加密,而后就构成了jwt的第三部分。因为base64是对称加密算法,因此能够轻松解密:所以咱们在负载部分不要将私密信息放置在里面,只须要把能验证惟一的标识信息添加就能够了。
有关base64,请参考:https://www.liaoxuefeng.com/w...
因为目前在学习DRF,因此我介绍一下怎样在DRF项目中使用JWT进行身份验证:
安装djangorestframework-jwt:后端
pip install djangorestframework-jwt
添加jwt认证类:api
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', ), }
添加jwt路由用于生成token:跨域
from rest_framework_jwt.views import obtain_jwt_token urlpatterns = [ url(r'^本身的路由/', obtain_jwt_token), ]
而后咱们就能够经过本身添加的路由并经过post添加username和password来获取到token了,在进行访问页面的时候咱们只须要在请求头中添加一个:Authorization: JWT <your_token>,就能够获得验证了。
固然咱们可能不止只须要token数据,还须要用户的ID,昵称等信息,那么咱们就须要手动生成token数据。服务器
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) #这里的用户对象就是在登陆视图中获取到的user token = jwt_encode_handler(payload)
固然咱们前面已经说明payload中最好不要存储私密信息,因此咱们在处理user前须要将不须要的字段删除:cookie
del user.set_password('') #固然这样作确定不科学,可是咱们因为这里没有场景,因此我先这样作,有须要的同窗能够私聊我。
而后咱们能够将返回到前端的数据进行保存,方便下次访问携带:
前端响应中使用的代码格式
关于session和local存储:https://www.cnblogs.com/st-le...
sessionStorage.变量名 = 变量值 // 保存数据 sessionStorage.变量名 // 读取数据 sessionStorage.clear() // 清除全部sessionStorage保存的数据 localStorage.变量名 = 变量值 // 保存数据 localStorage.变量名 // 读取数据 localStorage.clear() // 清除全部localStorage保存的数据
最后利用localStorage与sessionStorage读取数据的方式在须要后端验证的地方添加token数据。
全部配置参考:
JWT_AUTH = { 'JWT_ENCODE_HANDLER': 'rest_framework_jwt.utils.jwt_encode_handler', #加密处理函数 'JWT_DECODE_HANDLER': 'rest_framework_jwt.utils.jwt_decode_handler', #解密处理函数 'JWT_PAYLOAD_HANDLER': 'rest_framework_jwt.utils.jwt_payload_handler', #指定自定义函数以生成令牌有效内容 'JWT_PAYLOAD_GET_USER_ID_HANDLER': 'rest_framework_jwt.utils.jwt_get_user_id_from_payload_handler', #若是您的存储username方式与默认的有效负载处理程序不一样,请实现此功能以username从有效负载中获取 'JWT_RESPONSE_PAYLOAD_HANDLER': #负责控制登陆或刷新后返回的响应数据。覆盖以返回自定义响应 'rest_framework_jwt.utils.jwt_response_payload_handler', 'JWT_SECRET_KEY': settings.SECRET_KEY, #使用系统全局的SECRET_KEY 'JWT_GET_USER_SECRET_KEY': None, #这是JWT_SECRET_KEY的更强大版本。它是根据用户定义的,所以若是令牌被泄露,能够由全部者轻松更改。更改此值将使给定用户的全部令牌都没法使用。值应该是一个函数,接受用户做为惟一参数并返回它的密钥。 'JWT_PUBLIC_KEY': None, 'JWT_PRIVATE_KEY': None, 'JWT_ALGORITHM': 'HS256', #加密算法,必须设置为一个RS256,RS384或RS512。 'JWT_VERIFY': True, 'JWT_VERIFY_EXPIRATION': True, 'JWT_LEEWAY': 0, 'JWT_EXPIRATION_DELTA': datetime.timedelta(seconds=300), #设置有效期 'JWT_AUDIENCE': None, 'JWT_ISSUER': None, #这是一个字符串,将根据iss令牌字段进行检查。默认是None(不要检查issJWT) 'JWT_ALLOW_REFRESH': False, 'JWT_REFRESH_EXPIRATION_DELTA': datetime.timedelta(days=7), #设置令牌刷新时间,默认为datetime.timedelta(days=7)(7天) 'JWT_AUTH_HEADER_PREFIX': 'JWT', #您能够修改须要与令牌一块儿发送的Authorization标头值前缀。默认值为JWT,用于令牌和受权标头的另外一个常见值是Bearer。 'JWT_AUTH_COOKIE': None, #验证Authorization标头同时也验证cookie,通常不用 }