自动化测试平台开发(三):用户登录 drf+samplejwt
一、后端实现登录相关接口
- 安装drf和jwt
# drf pip install djangorestframework # jwt pip install djangorestframework-simplejwt
- 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__())
- 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)
- 定义登录的 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
- 编写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')
- 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
- django后台管理如下
- 使用postman 测试如下
user/login
user/info
二、前端修改登录请求地址
- 修改环境配置中 VUE_APP_BASE_API
# just a flag ENV = 'development' # base api VUE_APP_BASE_API = 'http://127.0.0.1:8000'
- 修改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) } )
- 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' }) }
- 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 --------