Django rest+jwt+vue-element-admin 實(shí)現(xiàn)用戶(hù)登錄

一捞奕、寫(xiě)在前面

這兩天重寫(xiě)了之前項(xiàng)目前臺(tái)與后臺(tái)對(duì)接的代碼稚虎。引入 Rest 框架和 samplejwt。在重寫(xiě)過(guò)程中參考網(wǎng)上文章發(fā)現(xiàn)很多文章多是 django 1.11和 jwt的文章坑鱼。所以紀(jì)錄分享

django 2.2 + samplejwt 與 vue-element-admin對(duì)接的方法如下持灰。

調(diào)試通過(guò)后的代碼分享在github,大家有興趣的可自行下載怎燥。
注:當(dāng)前僅調(diào)試登錄驗(yàn)證框架瘫筐,logout功能后續(xù)再補(bǔ)充。

后臺(tái)代碼地址:https://github.com/Sirius1942/banana/releases/tag/V0.0.1

前臺(tái)代碼地址:https://github.com/Sirius1942/rock/releases/tag/V0.0.1

代碼主要參考官方說(shuō)明:上面demo中很多參考官方示例代碼铐姚,有疑惑地方大家可自行查找

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

  2. django 官方文檔:擴(kuò)展和自定義后端https://docs.djangoproject.com/en/2.2/topics/auth/customizing/

  3. django-rest-framework-simplejwt 官方代碼說(shuō)明:https://github.com/davesque/django-rest-framework-simplejwt (建議看代碼和官方說(shuō)明策肝,網(wǎng)上資料比較少)

  4. django-cros 官方代碼及說(shuō)明:https://github.com/ottoyiu/django-cors-headers

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

以下主要參考的下面網(wǎng)上文章,感謝相關(guān)作者的支持

  1. http://www.reibang.com/p/3aa4a9625717

  2. http://www.reibang.com/p/51dafff7d1a9

  3. http://www.reibang.com/p/740a0320f960

二隐绵、主要修改部分及代碼實(shí)現(xiàn)過(guò)程

1之众、創(chuàng)建django-admin項(xiàng)目,新建user App 這里不詳細(xì)說(shuō)明依许,請(qǐng)參考相關(guān)文檔棺禾。

2、擴(kuò)展user 模型峭跳,滿(mǎn)足vue 需要:

from django.db import models
from django.contrib.auth.models import AbstractUser

 # Create your models here.

 #userProfile繼承AbstractUser分類(lèi)帘睦,進(jìn)行拓展
class UserProfile(AbstractUser):
    """
    用戶(hù)類(lèi)拓展
    """
    # 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

在設(shè)置文檔(settings.py)中 添加默認(rèn)類(lèi)

# 添加AUTH_USRE_MODEL 替換默認(rèn)的user
AUTH_USER_MODEL = 'user.UserProfile'

別忘檢查下是否添加了userapp

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

下面補(bǔ)充 login方法,正常情況下你應(yīng)該已經(jīng)完成用戶(hù)模型的字段的補(bǔ)充坦康,并且集成好了rest framework 和jwt 這時(shí)登錄

image.png

上面的圖片顯示已經(jīng)使用了 restframework 且jwt生效所以 直接訪問(wèn)users 想獲取用戶(hù)列表 由于沒(méi)有權(quán)限不能查看到用戶(hù)信息。

下面自定義登錄的 serializer 以便可以補(bǔ)充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)
        # ... 官方示例中上面的部分沒(méi)有生效
        # 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

注意滞欠,安官方說(shuō)明是不需要 validate 方法的。不過(guò)查看了 samplejwt的源代碼肆良,發(fā)現(xiàn)丟與token的封裝都是在這個(gè)方法中進(jìn)行的筛璧。所以按下面的方式封裝后成功。

以下是官方代碼截圖 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

補(bǔ)充封裝后的View方法

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

修改url 調(diào)用

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

完成以上應(yīng)該可以通過(guò)正確的 用戶(hù)名和密碼獲取到 token

使用postman 測(cè)試如下:


image.png

下面新增userinfo 接口

目前簡(jiǎn)單實(shí)現(xiàn)惹恃,直接加了一個(gè)接口夭谤。在 user views 中補(bǔ)充 get_user_info 方法

def get_user_info(request):

    User = get_user_model()
    if request.method=='GET':
        print("in get")
        # print(dir(request))
        #獲取請(qǐng)求參數(shù)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)

注:這里遇到個(gè)問(wèn)題是 request 方法中沒(méi)有 django 傳統(tǒng)的 META 方法,所以直接使用 JWTAuthentication.authenticate 方法會(huì)報(bào)錯(cuò)巫糙。這里手工調(diào)用 get_user方法朗儒,通過(guò) token獲取對(duì)應(yīng)的user對(duì)象。
另外: data 后續(xù)可以通過(guò)序列化優(yōu)化,這里先留一個(gè)坑后面填

繼續(xù)添加 user info url

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

以上登錄后通過(guò)token自動(dòng)獲取用戶(hù)信息后臺(tái)封裝完畢
下面來(lái)繼續(xù)修改前臺(tái)

前臺(tái)vue 代碼中主要需要修改 utils/request.js
補(bǔ)充消息頭:config.headers.Authorization = getToken()
config.headers['Content-Type'] = 'application/json'

// request interceptor
service.interceptors.request.use(
  config => {
    // 后臺(tái)使用jwt時(shí)候發(fā)送post請(qǐng)求必須使用 formdata模式
    if (config.method === 'post') {
      // JSON 轉(zhuǎn)換為 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 時(shí)修改 從 .access對(duì)象獲取 修改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) // 對(duì)接jwt token改成access 獲取token
        setToken(data.access)
        resolve()
      }).catch(error => {
        reject(error)
      })
    })
  },

其余由于后臺(tái)的role目前采用1個(gè)字段所以前臺(tái)獲取user地方臨時(shí)處理成醉锄,如果傳入的roles不是list 將其轉(zhuǎn)化成list 乏悄。注意下面代碼當(dāng)獲取不到role時(shí)還是會(huì)報(bào)錯(cuò),只要role不為空不會(huì)有問(wèn)題恳不,留個(gè)坑后面填

// 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)
        }

以上基本上是全部修改檩小,可能有記不清的地方,大家如果執(zhí)行代碼時(shí)候有問(wèn)題歡迎留言烟勋。

后續(xù)繼續(xù)填的坑规求,再慢慢更新:
1、logout —— auth與jwt卵惦、rest框架整合阻肿。
2、user與groups 關(guān)聯(lián)
3鸵荠、多roles 權(quán)限更改與判斷
4冕茅、前臺(tái)完整的用戶(hù)管理

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市蛹找,隨后出現(xiàn)的幾起案子姨伤,更是在濱河造成了極大的恐慌,老刑警劉巖庸疾,帶你破解...
    沈念sama閱讀 206,378評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件乍楚,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡届慈,警方通過(guò)查閱死者的電腦和手機(jī)徒溪,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)金顿,“玉大人臊泌,你說(shuō)我怎么就攤上這事∽岵穑” “怎么了渠概?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,702評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)嫂拴。 經(jīng)常有香客問(wèn)我播揪,道長(zhǎng),這世上最難降的妖魔是什么筒狠? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,259評(píng)論 1 279
  • 正文 為了忘掉前任猪狈,我火速辦了婚禮,結(jié)果婚禮上辩恼,老公的妹妹穿的比我還像新娘雇庙。我一直安慰自己谓形,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,263評(píng)論 5 371
  • 文/花漫 我一把揭開(kāi)白布状共。 她就那樣靜靜地躺著套耕,像睡著了一般。 火紅的嫁衣襯著肌膚如雪峡继。 梳的紋絲不亂的頭發(fā)上冯袍,一...
    開(kāi)封第一講書(shū)人閱讀 49,036評(píng)論 1 285
  • 那天,我揣著相機(jī)與錄音碾牌,去河邊找鬼康愤。 笑死,一個(gè)胖子當(dāng)著我的面吹牛舶吗,可吹牛的內(nèi)容都是我干的征冷。 我是一名探鬼主播,決...
    沈念sama閱讀 38,349評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼誓琼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼检激!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起腹侣,我...
    開(kāi)封第一講書(shū)人閱讀 36,979評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤叔收,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后傲隶,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體饺律,經(jīng)...
    沈念sama閱讀 43,469評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,938評(píng)論 2 323
  • 正文 我和宋清朗相戀三年跺株,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了复濒。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,059評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡乒省,死狀恐怖巧颈,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情袖扛,我是刑警寧澤洛二,帶...
    沈念sama閱讀 33,703評(píng)論 4 323
  • 正文 年R本政府宣布,位于F島的核電站攻锰,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏妓雾。R本人自食惡果不足惜娶吞,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,257評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望械姻。 院中可真熱鬧妒蛇,春花似錦机断、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,262評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至陶耍,卻和暖如春奋蔚,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背烈钞。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工泊碑, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人毯欣。 一個(gè)月前我還...
    沈念sama閱讀 45,501評(píng)論 2 354
  • 正文 我出身青樓馒过,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親酗钞。 傳聞我的和親對(duì)象是個(gè)殘疾皇子腹忽,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,792評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容