自动化测试平台开发(三):用户登录 drf+samplejwt

一、后端实现登录相关接口

  1. 安装drf和jwt
    # drf
    pip install djangorestframework
    
    # jwt
    pip install djangorestframework-simplejwt

     

  2. user_auth app中扩展User 模型,满足vue 需要,models.py
    from django.contrib.auth.models import User
    
    
    class UserProfile(models.Model):
        """用户类拓展"""
        user = models.OneToOneField(User, on_delete=models.CASCADE, related_name='profile')
        avatar = models.CharField(max_length=100, null=True, blank=True, verbose_name="avatar")
        role = models.CharField(max_length=10, default="tester", verbose_name="role")
    
        class Meta:
            verbose_name = "UserProfile"
            verbose_name_plural = verbose_name
    
        def __str__(self):
            return "{}".format(self.user.__str__())

     

  3. admin.py 重新注册User
    from django.contrib import admin
    from django.utils.text import capfirst
    from collections import OrderedDict as SortedDict
    
    from django.contrib.auth.admin import UserAdmin
    from django.contrib.auth.models import User
    
    from .models import UserProfile
    
    
    def find_model_index(name):
        count = 0
        for model, model_admin in admin.site._registry.items():
            if capfirst(model._meta.verbose_name_plural) == name:
                return count
            else:
                count += 1
        return count
    
    
    def index_decorator(func):
        def inner(*args, **kwargs):
            template_response = func(*args, **kwargs)
            for app in template_response.context_data['app_list']:
                app['models'].sort(key=lambda x: find_model_index(x['name']))
            return template_response
    
        return inner
    
    
    registry = SortedDict()
    registry.update(admin.site._registry)
    admin.site._registry = registry
    admin.site.index = index_decorator(admin.site.index)
    admin.site.app_index = index_decorator(admin.site.app_index)
    admin.site.site_header = '自动化测试平台-后台管理'
    admin.site.siteTitle = '后台管理'
    display = ()
    
    
    class UserProfileInline(admin.StackedInline):
        model = UserProfile
    
    
    class UserProfileAdmin(UserAdmin):
        inlines = [UserProfileInline, ]
    
    
    admin.site.unregister(User)
    admin.site.register(User, UserProfileAdmin)

     

  4. 定义登录的 serializer 以便可以补充vue所需要的字段
    from django.contrib.auth.models import User
    from rest_framework import serializers
    from rest_framework_simplejwt.serializers import TokenObtainPairSerializer
    
    from .models import UserProfile
    
    
    class UserSerializer(serializers.ModelSerializer):
    
        class Meta:
            model = User
            fields = ('id', 'username', 'first_name', 'last_name', 'email')
    
    
    class UserProfileSerializer(serializers.ModelSerializer):
        """
        扩展用户 信息序列化
        """
        user = UserSerializer()
        name = serializers.SerializerMethodField()
    
        class Meta:
            model = UserProfile
            fields = '__all__'
    
        def get_name(self, obj):
            return obj.user.username
    
    
    class MyTokenObtainPairSerializer(TokenObtainPairSerializer):
        @classmethod
        def get_token(cls, user):
            token = super().get_token(user)
            # Add custom claims
            # token['username'] = user.username
            # token['code'] = 20000
            # print(token)
            # ... 官方示例中上面的部分没有生效
            # print(token)
            return token
    
        def validate(self, attrs):
            data = super().validate(attrs)
            re_data = {'data': data, 'code': 20000, 'message': 'success'}
    
            return re_data
    
    
    if __name__ == '__main__':
        pass

     

  5. 编写view实现接口
    from rest_framework_simplejwt.views import TokenObtainPairView
    from .serializers import MyTokenObtainPairSerializer
    
    from utils.customized_drf import BaseViewSet  # 这里的BaseViewSet是对DRF的ModelViewSet进行了简单封装,添加了分页、filterset支持、输出格式化等
    from .models import UserProfile
    from .serializers import UserProfileSerializer
    
    
    class MyTokenObtainPairView(TokenObtainPairView):
        serializer_class = MyTokenObtainPairSerializer
    
    
    class UserProfileViewSet(BaseViewSet):
        serializer_class = UserProfileSerializer
        queryset = UserProfile.objects.all().order_by('id')

     

  6. urls.py添加路由
    from django.urls import path, include
    from rest_framework.routers import DefaultRouter
    
    from .views import MyTokenObtainPairView, UserProfileViewSet
    
    
    router = DefaultRouter()
    
    router.register(r'user/info', UserProfileViewSet, basename='retrieve'),
    router.register(r'user/list', UserProfileViewSet, basename='list'),
    router.register(r'user/add', UserProfileViewSet, basename='create'),
    router.register(r'user/update', UserProfileViewSet, basename='update'),
    router.register(r'user/del', UserProfileViewSet, basename='destroy')
    
    
    urlpatterns = [
        path('', include(router.urls)),
        path('user/login', MyTokenObtainPairView.as_view(), name='token_obtain_pair'),
    ]
    
    
    if __name__ == '__main__':
        pass

     

  7. django后台管理如下
  8. 使用postman 测试如下
    user/login

     

     user/info

二、前端修改登录请求地址

  1. 修改环境配置中 VUE_APP_BASE_API
    # just a flag
    ENV = 'development'
    
    # base api
    VUE_APP_BASE_API = 'http://127.0.0.1:8000'

     

  2. 修改request.js  request interceptor
    // request interceptor
    service.interceptors.request.use(
      config => {
        // do something before request is sent
    
        if (store.getters.token) {
          // let each request carry token
          // ['X-Token'] is a custom headers key
          // please modify it according to the actual situation
    
          // config.headers['X-Token'] = getToken() // remove
          config.headers.Authorization = getToken() // add
        }
        config.headers['Content-Type'] = 'application/json'
        return config
      },
      error => {
        // do something with request error
        console.log(error) // for debug
        return Promise.reject(error)
      }
    )

     

  3. api/user.js 修改请求地址
    export function login(data) {
      return request({
        url: '/api/user_auth/user/login',
        method: 'post',
        data
      })
    }
    
    export function getInfo(token) {
      return request({
        url: '/api/user_auth/user/info',
        method: 'get',
        params: { token }
      })
    }
    
    export function logout() {
      return request({
        url: '/api/user_auth/user/logout',
        method: 'post'
      })
    }

     

  4. store/modules/user.js 修改登录响应解析
    const actions = {
      // user login
      login({ commit }, userInfo) {
        const { username, password } = userInfo
        return new Promise((resolve, reject) => {
          login({ username: username.trim(), password: password }).then(response => {
            const { data } = response
            console.log(data)
            // commit('SET_TOKEN', data.token)
            // setToken(data.token)
            commit('SET_TOKEN', data.access) // 后端返回格式为 "data": { "refresh": "", "access": "" }
            setToken(data.access)
            resolve()
          }).catch(error => {
            reject(error)
          })
        })
      },

     

-------- THE END --------

posted @ 2021-11-28 16:49  徒手沉浮  阅读(743)  评论(0编辑  收藏  举报