来呀~
用户模块
Json Web Token认证
最常见的认证机制
Session认证
Token认证
Session认证
保持在服务端,增加服务器开销
分布式架构中,难以维持Session会话同步
CSRF攻击风险(跨站请求)
Token认证
保存在客户端
跨语言,跨平台
扩展性强
鉴权性能高
JWT(Json Web Token)
由三部分组成
header
声明类型
声明加密算法
base64加密,可以解密
playload
存放过期时间,签发用户等
可以添加用户的非敏感信息
base64加密,可以解密
signature
由三部分组成
使用base64加密之后的header + . + 使用base64加密之后的playload + 使用HS256算法加密,同时secret加盐处理
安装djangorestframework-jwt
$ pip install djangorestframework-jwt
使用
在 setting.py
中添加
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
# 使用JWT Token认证
'rest_framework_jwt.authentication.JSONWebTokenAuthentication',
# Basic类型的认证(账号和密码)
'rest_framework.authentication.SessionAuthentication',
# Session会话认证
'rest_framework.authentication.BasicAuthentication',
],
}
添加路由
用户处:user/urls.py
from django.urls import path
from rest_framework_jwt.views import obtain_jwt_token
urlpatterns = [
path('login/', obtain_jwt_token),
]
主路由:
ApiTest/urls.py
urlpatterns = [
path('users/', include('user.urls'))
]
不登录的访问
登录后的返回内容
HTTP 200 OK
Allow: POST, OPTIONS
Content-Type: application/json
Vary: Accept
{
"token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoxLCJ1c2VybmFtZSI6Inpob25neGluIiwiZXhwIjoxNTcyMzA5MzQ2LCJlbWFpbCI6IjQ5MDMzNjUzNEBxcS5jb20ifQ.ZDEeBAgSuPyvh1KBnF1sSY9w22guSRHXm8sbgqEWusg"
}
import base64
base64.b64decode('eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9')
# b'{"typ":"JWT","alg":"HS256"}'
认证过期时间
./site-packages/rest_framework_jwt/settings.py
第40行
'JWT_EXPIRATION_DELTA': datetime.timedelta(seconds=300),
Token默认过期时间5分钟
自行修改过期时间 ApiTest/settings.py
过期时间为1天
JWT_AUTH = {
'JWT_EXPIRATION_DELTA': datetime.timedelta(days=1)
}
请求Token 头
'JWT_AUTH_HEADER_PREFIX': 'JWT',
使用httpie发起包含token的内容
安装 httpie-jwt-auth
插件
$ export JWT_AUTH_TOKEN='你的token'
$ export JWT_AUTH_PREFIX='JWT'
$ http -A jwt :8000/projects/ page==2 size==2
修改载荷
def jwt_response_payload_handler(token, user=None, request=None):
"""
Returns the response data for both the login and refresh views.
Override to return a custom response such as including the
serialized representation of the User.
Example:
def jwt_response_payload_handler(token, user=None, request=None):
return {
'token': token,
'user': UserSerializer(user, context={'request': request}).data
}
"""
return {
'token': token
}
在 utils/jwt_handler.py
重写
def jwt_response_payload_handler(token, user=None, request=None):
return {
'token': token,
'user_id': user.id,
'username': user.username,
}
JWT_AUTH = {
'JWT_EXPIRATION_DELTA': datetime.timedelta(days=1),
'JWT_PAYLOAD_GET_USERNAME_HANDLER': 'utils.jwt_handler.jwt_response_payload_handler'
}
Django自带的用户模型
django.contrib.auth.models.User
查看settings.py可以发现,默认注册了 django.contrib.auth
注册
用户名(6-20位,不重复)
邮箱(符合邮箱格式)
密码(6-20位,和确认密码一致)
确认密码(6-20位,和密码一致)
user/serializers.py
from rest_framework import serializers
from django.contrib.auth.models import User
class RegisterSerializer(serializers.ModelSerializer):
password_conform = serializers.CharField(label='确认密码',
min_length=6,
max_length=20,
write_only=True,
help_text='确认密码',
error_messages={'min_length': '仅允许6~20个字符的确认密码',
'max_length': '仅允许6~20个字符的确认密码'}
)
token = serializers.CharField(label='生成token',
read_only=True)
class Meta:
model = User
fields = ('id', 'username', 'password', 'email', 'password_conform', 'token')
extra_kwargs = {
'username': {
'label': '用户名',
'help_text': '用户名',
'min_length': 6,
'max_length': 20,
'error_messages': {'min_length': '仅允许6~20个字符的用户名',
'max_length': '仅允许6~20个字符的用户名'}
},
'email': {
'label': '邮箱',
'help_text': '邮箱',
'write_only': True,
'required': True
},
'password': {
'label': '密码',
'help_text': '密码',
'write_only': True,
'min_length': 6,
'max_length': 20,
'error_messages': {'min_length': '仅允许6~20个字符的密码',
'max_length': '仅允许6~20个字符的密码'}
}
}
def create(self, validated_data):
pass
user/urls.py
from django.urls import path
from rest_framework_jwt.views import obtain_jwt_token
from . import views
urlpatterns = [
path('login/', obtain_jwt_token),
path('register/', views.RegisterView.as_view()),
]
user/views.py
from rest_framework.generics import CreateAPIView
from rest_framework_jwt.authentication import JSONWebTokenAuthentication
from user.serializers import RegisterSerializer
class RegisterView(CreateAPIView):
serializer_class = RegisterSerializer
authentication_classes = (JSONWebTokenAuthentication,)