INSTALLED_APPS = [ # ... 'rest_framework', ] MEDIA_URL = '/media/' MEDIA_ROOT = os.path.join(BASE_DIR, 'media') # 自定义用户表 AUTH_USER_MODEL = 'api.User'
from django.conf.urls import url, include from django.contrib import admin from django.views.static import serve from django.conf import settings urlpatterns = [ url(r'^admin/', admin.site.urls), # 路由分发 url(r'^api/', include('api.urls')), url(r'^media/(?P<path>).*', serve, {'document_root': settings.MEDIA_ROOT}), ]
from django.conf.urls import url, include from rest_framework.routers import SimpleRouter router = SimpleRouter() from . import views # 路由注册 # router.register('register', views.RegisterViewSet, 'register') urlpatterns = [ url('', include(router.urls)) ]
from django.contrib.auth.models import AbstractUser from django.db import models class User(AbstractUser): mobile = models.CharField(max_length=11, unique=True, verbose_name='移动电话') icon = models.ImageField(upload_to='icon', default='icon/default.png', verbose_name='头像') class Meta: db_table = 'o_user' # 定义表名 verbose_name_plural = '用户表' def __str__(self): return self.username class Book(models.Model): name = models.CharField(max_length=64, verbose_name='书名') class Meta: db_table = 'o_book' verbose_name_plural = '书表' def __str__(self): return self.name class Car(models.Model): name = models.CharField(max_length=64, verbose_name='车名') class Meta: db_table = 'o_car' verbose_name_plural = '车表' def __str__(self): return self.name
router.register('register', views.RegisterViewSet, 'register')
from rest_framework.viewsets import GenericViewSet, ModelViewSet from rest_framework import mixins from . import models, serializers class RegisterViewSet(GenericViewSet, mixins.CreateModelMixin): queryset = models.User.objects.filter(is_active=True).all() serializer_class = serializers.RegisterSerializer
from rest_framework import serializers from rest_framework.exceptions import ValidationError from . import models class RegisterSerializer(serializers.ModelSerializer): re_password = serializers.CharField(write_only=True, min_length=8, max_length=18) class Meta: model = models.User fields = ('username', 'password', 're_password', 'mobile') extra_kwargs = { 'password': { 'write_only': True, 'min_length': 8, 'max_length': 18 } } # username和mobile可以自定义局部钩子校验(省略) def validate(self, attrs): password = attrs.get('password') re_password = attrs.pop('re_password') if password != re_password: raise ValidationError({'re_password': 'password confirm error'}) return attrs # 需要重写create,创建用户需要密文 def create(self, validated_data): # 重写modelserializer创建表方法 return models.User.objects.create_user(**validated_data) # auth组件功能
router.register('user/center', views.UserCenterViewSet, 'center')
class UserCenterViewSet(GenericViewSet, mixins.RetrieveModelMixin): queryset = models.User.objects.filter(is_active=True).all() serializer_class = serializers.UserCenterSerializer
class UserCenterSerializer(serializers.ModelSerializer): class Meta: model = models.User fields = ('username', 'mobile', 'icon', 'email')
router.register('books', views.BookViewSet, 'book')
class BookViewSet(ModelViewSet): queryset = models.Book.objects.all() serializer_class = serializers.BookSerializer
class BookSerializer(serializers.ModelSerializer): class Meta: model = models.Book fields = ('name', )
""" 1)认证规则 2)如何自定义认证类 3)我们一般不需要自定义认证类,在settings中全局配置第三方 jwt 认证组件提供的认证类即可 """
""" 1)自定义认证类,继承 BaseAuthentication 类 2)必须重写 authenticate(self, request) 方法 没有认证信息,返回None:匿名用户(游客) => 匿名用户request.user也有值,就是"匿名对象(Anonymous)" 有认证信息,且通过,返回(user, token):合法用户 => user对象会存到request.user中 有认证信息,不通过,抛异常:非法用户 """
""" 1)权限规则 2)如何自定义权限类 3)我们一般在视图类中局部配置drf提供的权限类,但是也会自定义权限类完成局部配置 """
""" 1)自定义权限类,继承 BasePermission 类 2)必须重写 has_permission(self, request, view): 方法 设置权限条件,条件通过,返回True:有权限 设置权限条件,条件失败,返回False:有权限 3)drf提供的权限类: AllowAny:匿名与合法用户都可以 IsAuthenticated:必须登录,只有合法用户可以 IsAdminUser:必须是admin后台用户 IsAuthenticatedOrReadOnly:匿名只读,合法用户无限制 """
json web token
""" jwt优势 1)没有数据库写操作,高效 2)服务器不存token,低耗 3)签发校验都是算法,集群 """
""" 1)jwt分三段式:头.体.签名 (head.payload.sign) 2)头和体是可逆加密,让服务器可以反解出user对象;签名是不可逆加密,保证整个token的安全性的 3)头体签名三部分,都是采用json格式的字符串,进行加密,可逆加密一般采用base64算法,不可逆加密一般采用hash(md5)算法 4)头中的内容是基本信息:公司信息、项目组信息、token采用的加密方式信息 { "company": "公司信息", ... } 5)体中的内容是关键信息:用户主键、用户名、签发时客户端信息(设备号、地址)、过期时间 { "user_id": 1, ... } 6)签名中的内容时安全信息:头的加密结果 + 体的加密结果 + 服务器不对外公开的安全码 进行md5加密 { "head": "头的加密字符串", "payload": "体的加密字符串", "secret_key": "安全码" } """
""" 1)用基本信息存储json字典,采用base64算法加密得到 头字符串 2)用关键信息存储json字典,采用base64算法加密得到 体字符串 3)用头、体加密字符串再加安全码信息存储json字典,采用hash md5算法加密得到 签名字符串 账号密码就能根据User表得到user对象,形成的三段字符串用 . 拼接成token返回给前台 """
""" 1)将token按 . 拆分为三段字符串,第一段 头加密字符串 一般不需要做任何处理 2)第二段 体加密字符串,要反解出用户主键,通过主键从User表中就能得到登录用户,过期时间和设备信息都是安全信息,确保token没过期,且时同一设备来的 3)再用 第一段 + 第二段 + 服务器安全码 不可逆md5加密,与第三段 签名字符串 进行碰撞校验,通过后才能代表第二段校验得到的user对象就是合法的登录用户 """
""" 1)用账号密码访问登录接口,登录接口逻辑中调用 签发token 算法,得到token,返回给客户端,客户端自己存到cookies中 2)校验token的算法应该写在认证类中(在认证类中调用),全局配置给认证组件,所有视图类请求,都会进行认证校验,所以请求带了token,就会反解出user对象,在视图类中用request.user就能访问登录的用户 注:登录接口需要做 认证 + 权限 两个局部禁用 """
>: pip install djangorestframework-jwt
# api/urls.py urlpatterns = [ # ... url('^login/$', ObtainJSONWebToken.as_view()), ] # Postman请求:/api/login/,提供username和password即可
# drf-jwt的配置 import datetime # 配置必须放在drf配置的上面,才能起作用 JWT_AUTH = { # 配置过期时间 'JWT_EXPIRATION_DELTA': datetime.timedelta(days=7), } # drf配置(把配置放在最下方) REST_FRAMEWORK = { # 自定义三大认证配置类们 'DEFAULT_AUTHENTICATION_CLASSES': ['rest_framework_jwt.authentication.JSONWebTokenAuthentication'], # 'DEFAULT_PERMISSION_CLASSES': [], # 'DEFAULT_THROTTLE_CLASSES': [], }
from rest_framework.permissions import IsAuthenticated class UserCenterViewSet(GenericViewSet, mixins.RetrieveModelMixin): # 设置必须登录才能访问的权限类 permission_classes = [IsAuthenticated, ] queryset = models.User.objects.filter(is_active=True).all() serializer_class = serializers.UserCenterSerializer
""" 1)用 {"username": "你的用户", "password": "你的密码"} 访问 /api/login/ 接口等到 token 字符串 2)在请求头用 Authorization 携带 "jwt 登录得到的token" 访问 /api/user/center/1/ 接口访问个人中心 """
pycharm的debug介绍
1.向下一步,如果遇到调用方法,函数,当成一步走 2. 向下一步,如果遇到调用方法,函数,进入其中 3.向下一步,只走自己的代码(较少用到)
4.向下完成代码,直到下一个断点 5.显示所有断点(可编辑) 6.取消所有断点,再点击会再次出现断点 7.跳出当前方法,函数(完成),往下继续
""" 1)注册接口、个人中心接口、图书接口 2)认证组件 i)如何自定义认证类:继承谁、实现什么方法、方法体逻辑就是认证规则 ii)认证规则:游客、合法用户、方法用户 3)权限组件 i)如何自定义权限类:继承谁、实现什么方法、方法体逻辑就是权限规则 ii)权限规则:有权限、无权限 4)认证权限配置:局部 > 全局 > 默认 认证一般都是全局配置,所有登录注册接口要局部禁用 权限一般做局部配置 => 电商类项目,90%以上接口游客可以访问 权限一般做全局配置 => 邮箱项目,几乎所有接口都需要登录才能访问 5)jwt签发校验规则 6)drf-jwt框架的简单使用 """