美文网首页django
Django rest+jwt+vue-element-admi

Django rest+jwt+vue-element-admi

作者: 天狼星1942 | 来源:发表于2019-08-06 15:35 被阅读0次

    一、写在前面

    这两天重写了之前项目前台与后台对接的代码。引入 Rest 框架和 samplejwt。在重写过程中参考网上文章发现很多文章多是 django 1.11和 jwt的文章。所以纪录分享

    django 2.2 + samplejwt 与 vue-element-admin对接的方法如下。

    调试通过后的代码分享在github,大家有兴趣的可自行下载。
    注:当前仅调试登录验证框架,logout功能后续再补充。

    后台代码地址:https://github.com/Sirius1942/banana/releases/tag/V0.0.1

    前台代码地址:https://github.com/Sirius1942/rock/releases/tag/V0.0.1

    代码主要参考官方说明:上面demo中很多参考官方示例代码,有疑惑地方大家可自行查找

    1. django rest framework 官方文档:https://www.django-rest-framework.org/

    2. django 官方文档:扩展和自定义后端https://docs.djangoproject.com/en/2.2/topics/auth/customizing/

    3. django-rest-framework-simplejwt 官方代码说明:https://github.com/davesque/django-rest-framework-simplejwt (建议看代码和官方说明,网上资料比较少)

    4. django-cros 官方代码及说明:https://github.com/ottoyiu/django-cors-headers

    5. vue-element-admin 官方指南:https://panjiachen.github.io/vue-element-admin-site/zh/guide/

    以下主要参考的下面网上文章,感谢相关作者的支持

    1. https://www.jianshu.com/p/3aa4a9625717

    2. https://www.jianshu.com/p/51dafff7d1a9

    3. https://www.jianshu.com/p/740a0320f960

    二、主要修改部分及代码实现过程

    1、创建django-admin项目,新建user App 这里不详细说明,请参考相关文档。

    2、扩展user 模型,满足vue 需要:

    from django.db import models
    from django.contrib.auth.models import AbstractUser
    
     # Create your models here.
    
     #userProfile继承AbstractUser分类,进行拓展
    class UserProfile(AbstractUser):
        """
        用户类拓展
        """
        # name = models.CharField(max_length=30, null=True, blank=True, verbose_name="姓名" )
        avatar = models.CharField(max_length=100, null=True, blank=True, verbose_name="avatar")
        role = models.CharField(max_length=10, default="editor", verbose_name="role")
        introduction = models.TextField(max_length=500,null=True,blank=True, verbose_name="introduction")
    
        class Meta:
            verbose_name = "user"
            verbose_name_plural = verbose_name
    
        def __str__(self):
            return self.username
    

    在设置文档(settings.py)中 添加默认类

    # 添加AUTH_USRE_MODEL 替换默认的user
    AUTH_USER_MODEL = 'user.UserProfile'
    

    别忘检查下是否添加了userapp

    INSTALLED_APPS = [
        'user.apps.UserConfig',
    ]
    

    下面补充 login方法,正常情况下你应该已经完成用户模型的字段的补充,并且集成好了rest framework 和jwt 这时登录

    image.png

    上面的图片显示已经使用了 restframework 且jwt生效所以 直接访问users 想获取用户列表 由于没有权限不能查看到用户信息。

    下面自定义登录的 serializer 以便可以补充vue所需要的code,message 字段

    from rest_framework_simplejwt.serializers import TokenObtainPairSerializer
    
    class MyTokenObtainPairSerializer(TokenObtainPairSerializer):
        @classmethod
        def get_token(cls, user):
            print('in MyTokenObtainPairSerializer')
            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={}
            re_data['data']=data
            re_data['code']=20000
            re_data['message']='success'
    
            return re_data
    

    注意,安官方说明是不需要 validate 方法的。不过查看了 samplejwt的源代码,发现丢与token的封装都是在这个方法中进行的。所以按下面的方式封装后成功。

    以下是官方代码截图 get_token 方法仅返回加密的token而已

    class TokenObtainSlidingSerializer(TokenObtainSerializer):
        @classmethod
        def get_token(cls, user):
            return SlidingToken.for_user(user)
    
        def validate(self, attrs):
            data = super().validate(attrs)
    
            token = self.get_token(self.user)
    
            data['token'] = str(token)
    
            return data
    

    补充封装后的View方法

    #别忘了from引用刚刚新增的 serializer
    class MyTokenObtainPairView(TokenObtainPairView):
        serializer_class = MyTokenObtainPairSerializer
    

    修改url 调用

    urlpatterns = [
        ...
        path('user/login', MyTokenObtainPairView.as_view(), name='token_obtain_pair'),
       ....
    ]
    

    完成以上应该可以通过正确的 用户名和密码获取到 token

    使用postman 测试如下:


    image.png

    下面新增userinfo 接口

    目前简单实现,直接加了一个接口。在 user views 中补充 get_user_info 方法

    def get_user_info(request):
    
        User = get_user_model()
        if request.method=='GET':
            print("in get")
            # print(dir(request))
            #获取请求参数token的值
            token=request.headers.get('AUTHORIZATION')
            # test=request.META.get('CONTENT-TYPE')
            # print(test)
            # print(token)
    
            token_msg=authentication.JWTAuthentication().get_validated_token(token)
            print(token_msg)
            user_object=authentication.JWTAuthentication().get_user(token_msg)
            
            data = {"username":user_object.username,
                         "first_name":user_object.first_name,
                         "last_name": user_object.last_name,
                         "avatar":user_object.avatar,
                        #  "groups":user_object.groups,
                         "roles":user_object.role,
                         "introduction":user_object.introduction         
            }
            re_data={"data": data,
                     "code": 20000,
                     "message": "success"
            }
            return JsonResponse(re_data)
    

    注:这里遇到个问题是 request 方法中没有 django 传统的 META 方法,所以直接使用 JWTAuthentication.authenticate 方法会报错。这里手工调用 get_user方法,通过 token获取对应的user对象。
    另外: data 后续可以通过序列化优化,这里先留一个坑后面填

    继续添加 user info url

    path('user/info',views.get_user_info),
    

    以上登录后通过token自动获取用户信息后台封装完毕
    下面来继续修改前台

    前台vue 代码中主要需要修改 utils/request.js
    补充消息头:config.headers.Authorization = getToken()
    config.headers['Content-Type'] = 'application/json'

    // request interceptor
    service.interceptors.request.use(
      config => {
        // 后台使用jwt时候发送post请求必须使用 formdata模式
        if (config.method === 'post') {
          // JSON 转换为 FormData
          const formData = new FormData()
          Object.keys(config.data).forEach(key => formData.append(key, config.data[key]))
          config.data = formData
        }
        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()
          config.headers.Authorization = getToken()
        }
        config.headers['Content-Type'] = 'application/json'
        return config
      },
      error => {
        // do something with request error
        console.log(error) // for debug
        return Promise.reject(error)
      }
    )
    
    

    另外需要在获取token 时修改 从 .access对象获取 修改store/modules/user.js 中 set_token 中 data.access

    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('in store')
            commit('SET_TOKEN', data.access) // 对接jwt token改成access 获取token
            setToken(data.access)
            resolve()
          }).catch(error => {
            reject(error)
          })
        })
      },
    

    其余由于后台的role目前采用1个字段所以前台获取user地方临时处理成,如果传入的roles不是list 将其转化成list 。注意下面代码当获取不到role时还是会报错,只要role不为空不会有问题,留个坑后面填

    // roles must be a non-empty array
            if (!roles || roles.length <= 0) {
              // reject('getInfo: roles must be a non-null array!')
              var roles_list = []
              roles_list[0] = roles
              commit('SET_ROLES', roles_list)
            } else {
              commit('SET_ROLES', roles)
            }
    

    以上基本上是全部修改,可能有记不清的地方,大家如果执行代码时候有问题欢迎留言。

    后续继续填的坑,再慢慢更新:
    1、logout —— auth与jwt、rest框架整合。
    2、user与groups 关联
    3、多roles 权限更改与判断
    4、前台完整的用户管理

    相关文章

      网友评论

        本文标题:Django rest+jwt+vue-element-admi

        本文链接:https://www.haomeiwen.com/subject/kzgidctx.html