基于django-rest-framework的JWT的登陆与认证流程
JWT(Json web token)的介绍 分析
基于django-rest-framework的登陆认证方式常用的大体可分为四种:
1. BasicAuthentication:账号密码登陆验证
2. SessionAuthentication:基于session机制会话验证
3. TokenAuthentication: 基于令牌的验证
4. JSONWebTokenAuthentication:基于Json-Web-Token的验证
其中最常用的是JWT(Json-Web-Token),如果对JWT不理解的推荐一篇文章:前后端分离之JWT用户认证
JWT具有以下优点:
1. 签名的方式验证用户信息,安全性较之一般的认证高
2. 加密后的字符串保存于客户端浏览器中,减少服务器存储压力
3. 签名字符串中存储了用户部分的非私密信息,一定程度上能够减少服务器数据库查询用户信息的开销
缺点:
1. 采用对称加密,一旦被恶意用户获取到加密方法,就可以不断破解入侵获取信息,不过基本加密方法很难被破解
2. 加大了服务器的计算开销,–不过相对于磁盘开销,这都不算啥
总的来说,JWT没多少去缺点,所以很多公司都用这个业务做用户认证,当然,涉及到金钱的,还是选择非对称加密方式比较好。
JWT在前后端的逻辑分析:
图:
django-rest-framework_jwt的使用
使用详情参考django-rest-framework_jwt.
- 安装rest-frame-work—jwt
pip install djangorestframework-jwt
- 配置settings文件的认证选择
REST_FRAMEWORK = {
# 配置默认的认证方式 base:账号密码验证
#session:session_id认证
'DEFAULT_AUTHENTICATION_CLASSES': (
# drf的这一阶段主要是做验证,middleware的auth主要是设置session和user到request对象
# 默认的验证是按照验证列表从上到下的验证
'rest_framework.authentication.BasicAuthentication',
'rest_framework.authentication.SessionAuthentication',
"rest_framework_jwt.authentication.JSONWebTokenAuthentication",
)}
- 配置url(这里只针对做用户认证的)
from rest_framework_jwt.views import obtain_jwt_token
#...
urlpatterns = [
# ...
url(r'^api-token-auth/', obtain_jwt_token),
]
jwt在django-rest-framework中的实现原理
JWT实现的也是类似于session的一种会话保持机制,
登陆
用户在发起登陆请求的时候,相当于是给设定的”api-token-auth”这个url发起一个post请求,post的是两对键分别为”username”和”password”的json数据,url响应obtainJsonWebToken这个视图类,在这个视图内部定义了post方法去接受并处理数据。
这个视图类做了以下事情:
1. 序列化,将post过来的json数据转换成原生的python数据类型,序列化生成了JWT的token,并返回了user与token关联立的dict。
return {
'token': jwt_encode_handler(payload),
'user': user
}
2.序列化验证,并取出user和token值,生成响应体数据,然后实例化生成Response响应体对象:
if serializer.is_valid():
user = serializer.object.get('user') or request.user
token = serializer.object.get('token')
response_data = jwt_response_payload_handler(token, user, request)
response = Response(response_data)
前端在接受到这个响应后,会将username及token加入到cookie中,这样就完成了登陆的全过程
验证
登陆过的用户,在访问api的时候,都会进行一次token的验证,会话机制就是这样的一个原理,保持联系的最基本的原理就是每次交互都进行一次验证。
在django中就会涉及到一个中间件系统,首先会依次响应django中间件,全局拦截请求,将前端发过来的request中的用户加入到django的request体中,以及将token加入到request的META体中(django对api接口过来的request进行了一次重新的封装,drf对django的request进行了再一次封装,都是基于中间件系统)
然后响应view的中间件,将token和user从request中取出,进行jwt_token的解密验证。
那么这样就实现了JWT的验证过程。
django 中间件系统
django项目的settings文件中一般会配置一个middleware的列表,也就是中间件列表,如下:
MIDDLEWARE = [
'corsheaders.middleware.CorsMiddleware',
'django.middleware.security.SecurityMiddleware',
# 拦截请求,设置session到request
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
# 再次拦截请求,判断是否有session(上面已加入),设置user到request
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',]
一般而言,中间件就是一个类,继承自MiddlewareMixin,比如说SessionMiddleware:
class SessionMiddleware(MiddlewareMixin):
def __init__(self, get_response=None):
self.get_response = get_response
engine = import_module(settings.SESSION_ENGINE)
self.SessionStore = engine.SessionStore
def process_request(self, request):
session_key = request.COOKIES.get(settings.SESSION_COOKIE_NAME)
request.session = self.SessionStore(session_key)
def process_response(self, request, response):
"""
If request.session was modified, or if the configuration is to save the
session every time, save the changes and set a session cookie or delete
the session cookie if the session has been emptied.
重载了两个方法,分别是process_request和process_response方法,相当于很多框架生命周期里面的钩子函数,这两个方法如果被重载了,那么在request/response的过程中,肯定会被执行,在可以选择自己需要的中间件,也可以自己定义中间件取实现不同的功能。一般而言,被用作全局拦截器使用。