JWT-配置与使用
1.jwt的安装配置 .
1.1安装JWT
pip install djangorestframework-jwt==1.11.0
1.2 settings.py
配置jwt载荷中的有效期设置
# jwt载荷中的有效期设置 JWT_AUTH = { # 1.token前缀:headers中 Authorization 值的前缀 'JWT_AUTH_HEADER_PREFIX': 'JWT', # 2.token有效期:一天有效 'JWT_EXPIRATION_DELTA': datetime.timedelta(days=1), # 3.刷新token:允许使用旧的token换新token,接口对接需要设置为true 'JWT_ALLOW_REFRESH': True, # 4.token有效期:token在24小时内过期, 可续期token 'JWT_REFRESH_EXPIRATION_DELTA': datetime.timedelta(hours=24), # 5.自定义JWT载荷信息:自定义返回格式,需要手工创建 'JWT_RESPONSE_PAYLOAD_HANDLER': 'user.utils.jwt_response_payload_handler', }
1.3 settings.py
JWT结合DRF进行认证权限配置
""" Django settings for opwf project. Generated by 'django-admin startproject' using Django 2.0.13. For more information on this file, see https://docs.djangoproject.com/en/2.0/topics/settings/ For the full list of settings and their values, see https://docs.djangoproject.com/en/2.0/ref/settings/ """ import datetime import os, sys # Build paths inside the project like this: os.path.join(BASE_DIR, ...) BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) sys.path.insert(0, os.path.join(BASE_DIR, 'apps')) # Quick-start development settings - unsuitable for production # See https://docs.djangoproject.com/en/2.0/howto/deployment/checklist/ # SECURITY WARNING: keep the secret key used in production secret! SECRET_KEY = 'uorj1ni^mnut@wo@c%)iv)%5=8dxlml4-j0!f3b%4#f*8a5)3t' # SECURITY WARNING: don't run with debug turned on in production! DEBUG = True ALLOWED_HOSTS = ['*'] # Application definition INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'rest_framework', 'corsheaders', 'user.apps.UserConfig', 'workflow.apps.WorkflowConfig', 'workerorder.apps.WorkerorderConfig', # 'jwt', # 'rest_framework_jwt', # 'rest_framework.authentication' ] MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', 'corsheaders.middleware.CorsMiddleware', # 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', ] ROOT_URLCONF = 'opwf.urls' CORS_ORIGIN_ALLOW_ALL = True CORS_ORIGIN_WHITELIST = ( 'http://127.0.0.1:8080', 'http://localhost:8080', ) CORS_ALLOW_CREDENTIALS = True TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': [], 'APP_DIRS': True, 'OPTIONS': { 'context_processors': [ 'django.template.context_processors.debug', 'django.template.context_processors.request', 'django.contrib.auth.context_processors.auth', 'django.contrib.messages.context_processors.messages', ], }, }, ] WSGI_APPLICATION = 'opwf.wsgi.application' # Database # https://docs.djangoproject.com/en/2.0/ref/settings/#databases DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'opwf_db', 'USER': 'root', 'PASSWORD': '1', 'HOST': '127.0.0.1', 'PORT': '3306' } } # Password validation # https://docs.djangoproject.com/en/2.0/ref/settings/#auth-password-validators REST_FRAMEWORK = { # 文档报错: AttributeError: 'AutoSchema’ object has no attribute 'get_link’ # 用下面的设置可以解决 'DEFAULT_SCHEMA_CLASS': 'rest_framework.schemas.AutoSchema', # 默认设置是: # 'DEFAULT_SCHEMA_CLASS': 'rest_framework.schemas.openapi.AutoSchema', # 异常处理器 # 'EXCEPTION_HANDLER': 'user.utils.exception_handler', # Base API policies 默认渲染器类 'DEFAULT_RENDERER_CLASSES': [ 'rest_framework.renderers.JSONRenderer', 'rest_framework.renderers.BrowsableAPIRenderer', ], # 默认解析器类 'DEFAULT_PARSER_CLASSES': [ 'rest_framework.parsers.JSONParser', 'rest_framework.parsers.FormParser', 'rest_framework.parsers.MultiPartParser' ], # 1.认证器(全局) 'DEFAULT_AUTHENTICATION_CLASSES': [ 'rest_framework_jwt.authentication.JSONWebTokenAuthentication', # 在 DRF中配置JWT认证 # 'rest_framework.authentication.SessionAuthentication', # 使用session时的认证器 # 'rest_framework.authentication.BasicAuthentication' # 提交表单时的认证器 ], # 2.权限配置(全局): 顺序靠上的严格 'DEFAULT_PERMISSION_CLASSES': [ # 'rest_framework.permissions.IsAdminUser', # 管理员可以访问 # 'rest_framework.permissions.IsAuthenticated', # 认证用户可以访问 # 'rest_framework.permissions.IsAuthenticatedOrReadOnly', # 认证用户可以访问, 否则只能读取 # 'rest_framework.permissions.AllowAny', # 所有用户都可以访问 # 'user.utils.VipPermission', #自定义权限 ], # 3.限流(防爬虫) 'DEFAULT_THROTTLE_CLASSES': [ 'rest_framework.throttling.AnonRateThrottle', 'rest_framework.throttling.UserRateThrottle', ], # 3.1限流策略 # 'DEFAULT_THROTTLE_RATES': { # 'user': '100/hour', # 认证用户每小时100次 # 'anon': '300/day', # 未认证用户每天能访问3次 # }, 'DEFAULT_CONTENT_NEGOTIATION_CLASS': 'rest_framework.negotiation.DefaultContentNegotiation', 'DEFAULT_METADATA_CLASS': 'rest_framework.metadata.SimpleMetadata', 'DEFAULT_VERSIONING_CLASS': None, # 4.分页(全局):全局分页器, 例如 省市区的数据自定义分页器, 不需要分页 # 'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination', # # 每页返回数量 # 'PAGE_SIZE': 3, # 5.过滤器后端 'DEFAULT_FILTER_BACKENDS': [ 'django_filters.rest_framework.DjangoFilterBackend', # 'django_filters.rest_framework.backends.DjangoFilterBackend', 包路径有变化 ], # 5.1过滤排序(全局):Filtering 过滤排序 'SEARCH_PARAM': 'search', 'ORDERING_PARAM': 'ordering', 'NUM_PROXIES': None, # 6.版本控制:Versioning 接口版本控制 'DEFAULT_VERSION': None, 'ALLOWED_VERSIONS': None, 'VERSION_PARAM': 'version', # Authentication 认证 # 未认证用户使用的用户类型 'UNAUTHENTICATED_USER': 'django.contrib.auth.models.AnonymousUser', # 未认证用户使用的Token值 'UNAUTHENTICATED_TOKEN': None, # View configuration 'VIEW_NAME_FUNCTION': 'rest_framework.views.get_view_name', 'VIEW_DESCRIPTION_FUNCTION': 'rest_framework.views.get_view_description', 'NON_FIELD_ERRORS_KEY': 'non_field_errors', # Testing 'TEST_REQUEST_RENDERER_CLASSES': [ 'rest_framework.renderers.MultiPartRenderer', 'rest_framework.renderers.JSONRenderer' ], 'TEST_REQUEST_DEFAULT_FORMAT': 'multipart', # Hyperlink settings 'URL_FORMAT_OVERRIDE': 'format', 'FORMAT_SUFFIX_KWARG': 'format', 'URL_FIELD_NAME': 'url', # Encoding 'UNICODE_JSON': True, 'COMPACT_JSON': True, 'STRICT_JSON': True, 'COERCE_DECIMAL_TO_STRING': True, 'UPLOADED_FILES_USE_URL': True, # Browseable API 'HTML_SELECT_CUTOFF': 1000, 'HTML_SELECT_CUTOFF_TEXT': "More than {count} items...", # Schemas 'SCHEMA_COERCE_PATH_PK': True, 'SCHEMA_COERCE_METHOD_NAMES': { 'retrieve': 'read', 'destroy': 'delete' }, # 'Access-Control-Allow-Origin':'http://localhost:8080', # 'Access-Control-Allow-Credentials': True } AUTH_PASSWORD_VALIDATORS = [ { 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', }, { 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', }, { 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', }, { 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', }, ] # Internationalization # https://docs.djangoproject.com/en/2.0/topics/i18n/ LANGUAGE_CODE = 'zh-hans' TIME_ZONE = 'Asia/Shanghai' USE_I18N = True USE_L10N = True USE_TZ = False # Static files (CSS, JavaScript, Images) # https://docs.djangoproject.com/en/2.0/howto/static-files/ STATIC_URL = '/static/' AUTH_USER_MODEL = 'user.User' # jwt载荷中的有效期设置 JWT_AUTH = { # 1.token前缀:headers中 Authorization 值的前缀 'JWT_AUTH_HEADER_PREFIX': 'JWT', # 2.token有效期:一天有效 'JWT_EXPIRATION_DELTA': datetime.timedelta(days=1), # 3.刷新token:允许使用旧的token换新token 'JWT_ALLOW_REFRESH': True, # 4.token有效期:token在24小时内过期, 可续期token 'JWT_REFRESH_EXPIRATION_DELTA': datetime.timedelta(hours=24), # 5.自定义JWT载荷信息:自定义返回格式,需要手工创建 'JWT_RESPONSE_PAYLOAD_HANDLER': 'user.utils.jwt_response_payload_handler', }
settings.py
1.4 user/urls.py
增加获取token接口和刷新token接口
from django.urls import include, path from rest_framework.authtoken.views import obtain_auth_token from user import views from rest_framework.routers import SimpleRouter, DefaultRouter from rest_framework_jwt.views import obtain_jwt_token, refresh_jwt_token # 自动生成路由方法, 必须使用视图集 # router = SimpleRouter() # 没有根路由 /user/ 无法识别 router = DefaultRouter() # 有根路由 router.register(r'user', views.UserViewSet) urlpatterns = [ path('index/', views.index), # 函数视图 path('login/', obtain_jwt_token), # 获取token,登录视图 path('register/',views.Register.as_view()), #注册用户 path('refresh/', refresh_jwt_token), # 刷新token path('api-auth/', include('rest_framework.urls', namespace='rest_framework')), # 认证地址 ] urlpatterns += router.urls # 模块地址 # print(router.urls) # obtain_jwt_token = ObtainJSONWebToken.as_view() # 获取token # refresh_jwt_token = RefreshJSONWebToken.as_view() # 刷新token # verify_jwt_token = VerifyJSONWebToken.as_view() # 修改token
1.5 user/utils.py 从写jwt_response_payload_handler
def jwt_response_payload_handler(token, user=None, request=None, role=None): """ 自定义jwt认证成功返回数据 :token 返回的jwt :user 当前登录的用户信息[对象] :request 当前本次客户端提交过来的数据 :role 角色 """ if user.first_name: name = user.first_name else: name = user.username return { 'authenticated': 'true', 'id': user.id, "role": role, 'name': name, 'username': user.username, 'email': user.email, 'token': token, }
1.6 user/utils.py 生成token
#生成jwt_token def create_token(user): #user:接收的用户对象 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) return token
1.7 重写django认证
settings.py AUTHENTICATION_BACKENDS = ['user.utils.EmailAuthBackend']
user/utils.py #重写django认证 class EmailAuthBackend: def authenticate(self, request, username=None, password=None): try: user = User.objects.get(username=username) except Exception as e: user = None if not user: try: user = User.objects.get(email=username) except Exception as e: user = None if not user: try: user = User.objects.get(phone=username) except Exception as e: user = None if user and user.check_password(password): return user else: return None def get_user(self, user_id): try: return User.objects.get(pk=user_id) except User.DoesNotExist: return None
2.代码实践 .
from django.db import models # Create your models here. from django.contrib.auth.models import AbstractUser class Vip(models.Model): vip_choices = ( ('1','普通会员'), ('2','高级会员') ) vip_name = models.CharField(verbose_name='vip名称',max_length=20) vip_type = models.CharField(verbose_name='vip种类',max_length=20,choices=vip_choices) desc = models.CharField(verbose_name='vip描述',max_length=255) class Meta: db_table = 'tb_vip' verbose_name = 'Vip表' class User(AbstractUser): nike_name = models.CharField(verbose_name='昵称',max_length=30,null=True) phone = models.CharField(verbose_name='手机号',max_length=30,null=True) email = models.CharField(verbose_name='邮箱',max_length=255,null=True) address = models.CharField(verbose_name='地址',max_length=255,null=True) vip = models.ForeignKey(Vip,on_delete=models.CASCADE,null=True,default=None) class Meta: db_table = 'tb_user' verbose_name = '用户表'
user/models.py
from django.urls import path from . import views from rest_framework_jwt.views import obtain_jwt_token urlpatterns = [ path('register/',views.Register.as_view()), #注册 path('login/',obtain_jwt_token), #登录 path('test/',views.Test.as_view()), #测试权限用的 ]
user/urls.py
from django.shortcuts import render # Create your views here. from rest_framework.views import APIView,Response from .serializers import * from .models import * from user.utils import create_token from rest_framework.permissions import IsAuthenticated,IsAdminUser,AllowAny from user.utils import VipPermission class Register(APIView): def post(self,requset): print(requset.data) username = requset.data.get('username') password = requset.data.get('password') phone = requset.data.get('phone') email = requset.data.get('email') address = requset.data.get('address') if not all([username,password,phone,email,address]): return Response({'msg':'数据不完整','code':400}) #create添加 # user_obj = User.objects.create(username=username,password=make_password(password), # phone=phone,email=email,address=address) # # token = create_token(user_obj) # # data = { # 'id':user_obj.pk, # 'username':user_obj.username, # 'phone':user_obj.phone, # 'email':user_obj.email, # 'address':user_obj.address, # 'token':token # } #序列化添加 user_serializer = UserSerializers(data=requset.data) user_serializer.is_valid() user_serializer.save() return Response({'msg':'注册成功','code':200,'data':user_serializer.data}) class Test(APIView): # permission_classes = (IsAuthenticated,) #只有认证用户可以访问 # permission_classes = (IsAdminUser,) #只有管理员用户可以访问 # permission_classes = (AllowAny,) #所有用户都可以访问 # permission_classes = (VipPermission,) #自定义权限 def get(self,request): return Response({'msg':'ok','code':200})
user/views.py
from rest_framework_jwt.serializers import api_settings from rest_framework.permissions import BasePermission from .models import * #生成jwt_token def create_token(user): #user:接收的用户对象 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) return token #重写payload_handler的载荷信息 def jwt_response_payload_handler(token,user=None,request=None): return { 'id':user.pk, 'username':user.username, 'token':token } #自定义权限 需要继承BasePermission class VipPermission(BasePermission): message = '只有黄金VIP才能访问' def has_permission(self, request, view): print(request.user) user_obj = User.objects.filter(id=request.user.pk).first() if user_obj.vip.id !=2: #判断关联字段是否是黄金vip return False return True
user/utils.py
from django.contrib.auth.hashers import make_password from rest_framework import serializers from .models import * from user.utils import create_token class UserSerializers(serializers.Serializer): username = serializers.CharField(max_length=30) phone = serializers.CharField(max_length=30) email = serializers.CharField(max_length=30) address = serializers.CharField(max_length=30) password = serializers.CharField(max_length=128) token = serializers.CharField(max_length=128,read_only=True) def create(self, validated_data): #1.make_password加密: validated_data["password"] = make_password(validated_data.get('password')) user_obj = User.objects.create(**validated_data) token = create_token(user_obj) user_obj.token = token return user_obj #2.set_password加密 # user_obj = User.objects.create(**validated_data) # user_obj.set_password(validated_data.get('password')) # user_obj.save() # token = create_token(user_obj) # user_obj.token = token # return user_obj
user/serializers.py
3.postman测试接口 .
3.1 测试注册接口
http://127.0.0.1:8000/user/register/
3.2 测试登录接口
http://127.0.0.1:8000/user/login/
3.2 测试登录接口
http://127.0.0.1:8000/user/test/
赞 (0)