django-rest-framework自定义用户表及simplejwt使用记录

django-rest-framework及simplejwt使用记录

安装

首次使用需要安装django-rest-framework及jwt相关包

pip install djangorestframework
pip install djangorestframework-simplejwt

settings文件增加配置

INSTALLED_APPS =[
...
...
'rest_framework'
'app01'
]

REST_FRAMEWORK = {
     
    'DEFAULT_PERMISSION_CLASSES': ('rest_framework.permissions.IsAuthenticated',),
    # 'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
    # 'PAGE_SIZE': 10,
    # 用户登陆认证方式
    # SessionAuthentication, BasicAuthentication,为了兼容drf自带的页面认证方式
    # 若使用drf默认登录认证,不能使用自定义表的用户信息,只可以用默认User表用户登录,通过python manage.py createsuperuser创建
    # 'DEFAULT_AUTHENTICATION_CLASSES': (
    #     'rest_framework.authentication.SessionAuthentication',
    #     'rest_framework.authentication.BasicAuthentication',
    # )
}
# jwt
SIMPLE_JWT = {
     
    'ACCESS_TOKEN_LIFETIME': datetime.timedelta(minutes=30),
    'REFRESH_TOKEN_LIFETIME': datetime.timedelta(days=1),
}

jwt登录认证

由于jwt默认使用django自带的User表,若使用自定义User表需要改造获取token的视图,继承官方文档提供的视图TokenObtainPairSerializer,TokenObtainPairView
自定义的User表,增加is_authenticated方法

class User(models.Model):
    code = models.CharField(max_length=64, unique=True, verbose_name='用户编码')
    name = models.CharField(max_length=128, verbose_name='用户中文名')
    password = models.CharField(max_length=256, verbose_name='密码')
    email = models.EmailField(unique=True, verbose_name='邮箱')
    enabled = models.IntegerField(default=1, verbose_name='是否启用', choices=((1, '启用'), (0, '停用')))

	@property
    def is_authenticated(self):
        """
        Always return True. This is a way to tell if the user has been
        authenticated in templates.
        """
        return True

创建app01/utils/Authentication.py

from rest_framework_simplejwt.authentication import JWTAuthentication
from rest_framework_simplejwt.exceptions import InvalidToken, AuthenticationFailed
from rest_framework_simplejwt.serializers import TokenObtainPairSerializer
from rest_framework_simplejwt.views import TokenObtainPairView
from rest_framework import exceptions

from django.utils.translation import gettext_lazy as _

from app01.models import User


class MyTokenObtainPairSerializer(TokenObtainPairSerializer):
    """
    自定义登录认证,使用自有用户表
    """
    username_field = 'username'

    def validate(self, attrs):
        authenticate_kwargs = {
     self.username_field: attrs[self.username_field], 'password': attrs['password']}
        print(authenticate_kwargs)
        try:
            user = User.objects.get(**authenticate_kwargs)
        except Exception as e:
            raise exceptions.NotFound(e.args[0])

        refresh = self.get_token(user)

        data = {
     "userId": user.id, "token": str(refresh.access_token), "refresh": str(refresh)}
        return data


class MyTokenObtainPairView(TokenObtainPairView):
    serializer_class = MyTokenObtainPairSerializer


class MyJWTAuthentication(JWTAuthentication):
    '''
    修改JWT认证类,返回自定义User表对象
    '''
    def get_user(self, validated_token):
        try:
            user_id = validated_token['user_id']
        except KeyError:
            raise InvalidToken(_('Token contained no recognizable user identification'))

        try:
            user = User.objects.get(**{
     'id': user_id})
        except User.DoesNotExist:
            raise AuthenticationFailed(_('User not found'), code='user_not_found')

        return user

修改viewset的authentication_classes,增加调用MyJWTAuthentication即可

class UserViewSet(ModelViewSet):
    queryset = User.objects.all().order_by('id')
    serializer_class = UserSerializer
    permission_classes = permission
    authentication_classes = [MyJWTAuthentication, SessionAuthentication, BasicAuthentication]

app01/views.py

class TestView(views.APIView):
    # permission_classes = [permissions.AllowAny]
    # authentication_classes = [JWTAuthentication, SessionAuthentication, BasicAuthentication]

    def get(self, request, *args, **kwargs):
        # print('authenticate: ', request.successful_authenticator.authenticate(request))
        # print('authenticate_header: ', request.successful_authenticator.authenticate_header(request))
        # print('get_header: ', request.successful_authenticator.get_header(request))
        # print('get_raw_token: ',
        #       request.successful_authenticator.get_raw_token(request.successful_authenticator.get_header(request)))
        # print('get_validated_token: ', request.successful_authenticator.get_validated_token(
        #     request.successful_authenticator.get_raw_token(request.successful_authenticator.get_header(request))))
        # print('get_user: ', request.successful_authenticator.get_user(
        #     request.successful_authenticator.get_validated_token(
        #         request.successful_authenticator.get_raw_token(request.successful_authenticator.get_header(request)))))
        # print('www_authenticate_realm: ', request.successful_authenticator.www_authenticate_realm)
        return Response('OK')

    def post(self, request, *args, **kwargs):
        return Response('OK')

修改app01/urls.py

urlpatterns = [
    path('', include(routers.urls)),
    # jwt
    path('login/', MyTokenObtainPairView.as_view(), name='login'),
    path('test/', views.TestView.as_view(), name='test'),
    # jwt
    path('api-auth/', include('rest_framework.urls', namespace='rest_framework'))
]

验证登录

浏览器打开 http://127.0.0.1:8000/test/ 返回ok,代表drf框架已经正常了
下面打开postman登录获取token令牌
django-rest-framework自定义用户表及simplejwt使用记录_第1张图片
没有意外情况就可以成功返回token

获取其它表的序列化数据

获取其它表的序列化数据需要带上获取的token值
django-rest-framework自定义用户表及simplejwt使用记录_第2张图片

特殊Model的序列化

普通的Model表的api很简单,参考django-rest-framework官方文档即可,下面记录下关于多对多ManyToMany关系的编写

class Role(models.Model):
    role_name = models.CharField(max_length=128, unique=True, verbose_name="组名")
    permission = models.ManyToManyField('Permission', blank=True, verbose_name="关联权限")
    server_group = models.ManyToManyField('ServerGroup', blank=True, verbose_name="关联服务器组")
    memo = models.TextField(blank=True, null=True, verbose_name="备注")
    c_time = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')

直接使用默认的ModelSerializer会报错,查找官方文档找到一个SlugRelatedField字段可以通过关联查询方式序列化,
slug_field对应的是关联表的显示字段

class RoleSerializer(serializers.HyperlinkedModelSerializer):
    permission = serializers.SlugRelatedField(slug_field='title', many=True, queryset=Permission.objects.all())
    server_group = serializers.SlugRelatedField(slug_field='name', many=True, queryset=ServerGroup.objects.all())

    class Meta:
        model = Role
        fields = ['url', 'role_name', 'permission', 'server_group', 'memo', 'c_time']

有其他问题后续研究后继续更新

你可能感兴趣的:(python,python,jwt,django,restful)