Django+Vue,前后端分离,实现用户权限认证

网上教程一大堆,要么思路不够清晰,要么给你扔一大段代码,只有几行注释。。。。
看完我这个,你奶奶来都能实现前后端分离用户权限认证。

Django

采用token认证方式,使用 rest_framework_simplejwt 库配置权限认证。
需要注意的是,使用rest_framework_simplejwt 进行身份认证时并不需要去对数据库进行查询校验,所以并不会将token保存在数据库中。

1、安装第三方库:

pip install rest_framework

pip install rest_framework_simplejwt

2、项目根目录settings.py配置文件中写入以下配置项

//settings.py 

//INSTALLED_APPS中添加注册信息 
INSTALLED_APPS = [ 
    ....... 
    'rest_framework', 
    'rest_framework.authtoken',
 ] 

//REST_FRAMEWORK中全局配置认证方式、权限方式。局部认证网上一大堆,请自查……^ ^ 
//如settings.py文件中没有REST_FRAMEWORK,请自主写入 
REST_FRAMEWORK = { 
    // DEFAULT_PERMISSION_CLASSES设置默认的权限类,通过认证后赋予用户的权限 
    'DEFAULT_PERMISSION_CLASSES': ( 'rest_framework.permissions.IsAuthenticated', ), 
    // DEFAULT_AUTHENTICATION_CLASSES设置默认的认证类,这里用token,也可以设置session或自定义的认证                              
    'DEFAULT_AUTHENTICATION_CLASSES': ( 
    'rest_framework_simplejwt.authentication.JWTAuthentication', # 进行token认证 
    ) 
} 
//SIMPLE_JWT是token配置项,参数很多,不一一列举,请自查……^ ^ 
import datetime //导入datetime库生成时间参数 
SIMPLE_JWT = {
     //ACCESS_TOKEN_LIFETIME设置token令牌有效时间 
     //rest_framework_simplejwt官方默认有效时间是5分钟,这里改成15天
     'ACCESS_TOKEN_LIFETIME': datetime.timedelta(days=15), 
    //REFRESH_TOKEN_LIFETIME设置token刷新令牌有效时间 
    'REFRESH_TOKEN_LIFETIME': datetime.timedelta(days=15), 
} 
//AUTH_USER_MODEL是配置默认的校验数据表,取决你自己的用户表 
//参数格式为:(你自己创建的app文件夹名称).(app文件夹中models.py中用户表名称) 
//以下 login 为我创建的app文件夹名称, UserInfo 为login下的models.py中的用户表名称 
AUTH_USER_MODEL = 'login.UserInfo' 

//AUTH_PASSWORD_VALIDATORS是配置创建用户时的默认参数,这里密码长度最小为5位字符,系统默认时8位 AUTH_PASSWORD_VALIDATORS = [
     { 
          //设置密码最小长度为5 
          'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', 
          'OPTIONS': {'min_length': 5} 
      }, 
]

3、项目根目录urls.py文件写入获取token、刷新token的路由

from django.contrib import admin 
from django.urls import path, include 
from rest_framework_simplejwt.views import TokenObtainPairView,TokenRefreshView 

urlpatterns = ( 
    path('admin/', admin.site.urls),
    # 验证用户并生成token 
    path('token/', TokenObtainPairView.as_view(),name="token_obtain_pair"), 
    # 刷新token 
    path('token/refresh/', TokenRefreshView.as_view(), name='token_refresh'), 
)

4、用postman测试一下是否能成功获取token、刷新token
注意!请确保已经创建了用户,这里是用django自带的用户体系。
创建超级用户,命令行输入:python3 manage.py createsuperuser
创建完毕之后,用户数据信息会生成在用户数据表中,在之前settings.py文件中配置的AUTH_USER_MODEL = 'login.UserInfo'
往后的用户信息认证,django都会去校验该用户数据表。


image.jpeg

到这里就成功获取token令牌了。
headers:Content-Type:application/json
body:{"username": "admin", "password": "admin"} //参数名一定要是username、password

5、自定义获取token的响应信息
这里是直接修改rest_framework_simplejwt库的原文件,官方文档的方法我不会用,嘻嘻。
文件路径是rest_framework_simplejwt/serializers.py
serializers.py中找到TokenObtainPairSerializer这个类


image.jpeg
//初始只有两个字段信息:access和refresh 
data['access'] = str(refresh.access_token) 
data['refresh'] = str(refresh) 
//往下可自行添加需要返回的信息,注意返回的信息字段必须存在于你的用户数据表内! 
data['自定义返回key'] = 自定义返回value,value取值方法为self.user.用户表字段名 
import datetime time = datetime.datetime.today().strftime("%Y-%m-%d %H:%M:%S") 
data['message'] = 'success' 
data['status'] = 200 
data['now'] = time 
data['data'] = { 'user_id':self.user.id, 'username':self.user.sl_name, 'department':self.user.department, } 
//保存,再用postman请求一次token接口,就能看到自定义返回的信息了

6、生成token后,请求其他接口时,用户信息认证。重点来了!!!!

这里刚开始的时候,我查了大量了网上教程,99%的教程基本上到了获取token就结束了,没有详细说接下来怎么通过生成的token来验证用户接下来的接口请求。

这对于初学者来说,是一脸懵逼的,是非常不友好的,就好比话说了一半,剩下的一半就不说了。

# 在你的app文件下下的views.py中写入 
# 首先,我们刚开始写接口的时候是这样的,这样是没有身份验证的,直接就访问成功 
def aa(request): 
    """业务逻辑""" 
    return XXXXX 
# 现在生成了token之后,我们应该这样写: 
# 把函数方法写成类的形式,继承APIView类。 
# APIView是REST framework提供的所有视图的基类, 继承自Django的View,对Django中的View进行了拓展,具备了认证、授权、限流、不同请求数据的解析的功能。 
from rest_framework.views import APIView 
class Aa(APIView): 
    def get(self,request): # 请求为get时的业务逻辑 
        """业务逻辑""" 
        return XXXXX 
    def post(self.request): # 请求为post时的业务逻辑 
        """业务逻辑""" 
        return XXXXX 
# 接着在你的app文件下下的urls.py中写入 
urlpatterns = [ 
    path('aa', views.Aa.as_view(), name='aa') # 注意一定要有as_view(),才能将接口传过来的参数传递给Aa这个类
 ] 
# 记得在根目录的urls.py中配置你的项目路由,如根目录配置如下: 
urlpatterns = ( 
    path('login/', include('login.urls'))
 ) 
则可自行用postman测试携带token和不携带token请求 http://127.0.0.1:8000/login/aa

7、有关rest_framework_simplejwt的一个小坑,极易误导新手!!
要说的是TokenVerifyView这个视图,
网上的教程,99.999999%没有说这个视图到底是个啥!


image.png

这个视图是干嘛的,源码中是这样写的

class TokenVerifyView(TokenViewBase):
    """
    Takes a token and indicates if it is valid.  This view provides no
    information about a token's fitness for a particular use.
    """
    serializer_class = serializers.TokenVerifySerializer

翻译出来就是:获取令牌并指示它是否有效。此视图不提供关于令牌适用于特定用途的信息。
这个视图只是检验你当前的token是否有效,别无他用。
这个视图可以用于vue前端写路由守卫的时候用上。
接下来说这个视图坑在哪里,首先用postman请求一下这个token验证接口。



body只需要传{"token":"(你生成的token)"}
可以看到respones返回了一个空字典{},这里是什么情况,真实情况就是!!!!
验证token有效,就是返回一个空字典{}!!!!可以看一下源码就知道。


image.png

源码中写的就是验证token有效那就return一个{} 。。。。。。
你可以在这个空字典中自定义任何返回内容。。。。。
这里算是个小坑。

到这里有关Django采用rest_framework_simplejwt实现权限验证就结束了。

Vue

接下来就Vue中如何实现前端如何保存请求登录接口成功后,后端返回的token,在后续请求中往headers中添加token发送给后端进行用户信息认证。验证通过,走业务逻辑。验证不通过,返回登录页让用户重新登录再次获取有效token。

1、封装一个自定义的axios请求
先在src目录下新建一个utils文件夹(名字可自定义),在utils文件夹中新建两个js文件(名字可自定义)


image.jpeg

request.js是封装axios请求的js文件,storage.js是如何处理token的js文件。
这里我们先处理token,封装三个方法,getItem获取保存的token,setItem存储token,removeitem删除token

/*storage.js*/ 
/* 
封装模块 使用localStorage保存token到localStorage里,只要不删除,永久存在,实现持久化 从localStorage中取出一项数据 名字叫name(自定义名称) 
*/ 
export const getItem = name => { 
    return JSON.parse(localStorage.getItem(name)); 
}; 

/* 
向localStorage中设置一项数据 名字为name里面设置值为obj 
*/ 
export const setItem = (name, obj) => { 
    localStorage.setItem(name, JSON.stringify(obj)); 
}; 

/* 
删除
 */ 
export const removeitem = name => { 
    localStorage.removeItem(name); 
};

然后封装axios请求

//request.js 
/*
 对axios进行二次封装 请求拦截器增加token 响应拦截器处理大数据 
*/ 
import store from "@/store/index"; 
import axios from "axios"; 
/* 
自定义写法:const xxx = axios.create({}) 一个项目中可能有不同的服务器基础地址 就要用自定义写法设置不同的服务器基础地址 
*/ 
const instance = axios.create({ baseURL: "http://127.0.0.1:8000" }); 
// 在instance(这是上面定义的自定义axios请求名称)上添加请求拦截器 补充请求头token信息 
instance.interceptors.request.use( function(config) { 
    // 从vuex中取出token,这里先这样写,下面会说这里是怎么回事 
    const token = store.state.token; 
    // 如果有token则添加到headers中 
    if (token) { 
        config.headers.Authorization = `JWT ${token}`; //这里的JWT是后端默认的token需要携带的字段,可在后端自定义,中间空格不能删除 } 
        return config; }, function(error) { return Promise.reject(error); } ); export default instance;

2、打开store/index.js文件,在文件中的vuex里存储token,用的是上面storage.js中自定义的getItem方法。
vuex是什么,请百度自行学习,不过多赘述。

import Vue from "vue"; 
import Vuex from "vuex"; 
import { setItem, getItem } from "@/utils/storage"; //导入刚才定义token存储、获取方法 
Vue.use(Vuex); 
export default new Vuex.Store({ 
    state: {
         // 保存公共数据 在设置vuex中的初值时,先从本地存储中取,如果取不到,则初始为空 
        token: getItem("token") || {} 
    }, 
    mutations: { 
        mSetTokenInfo(state, tokenObj) { 
            state.token = tokenObj; // 刷新会丢失所以进行持久化 调用上面storage.js文件里setItem方法保存token 
            setItem("token", tokenObj); 
        }
     }, 
    actions: {}, 
    modules: {} 
});

3、用上面自定义的instance方法,发起axios请求登录接口,并保存返回的token

//点击【登录】后用自定义的instance方法发送axios请求 
login_ButtonCheck: function() { 
    const usr_val = $("#usr").val(); 
    const pwd_val = $("#pwd").val(); 
    //自定义的instance方法向后端发起post请求,常规axios写法为 this.axios.post 
    instance .post("/login/", { username: usr_val, password: pwd_val }) 
    .then(res => { 
        //登录成功 
        //用this.$store.commit调用上面store/index.js文件中vuex里自定义的mSetTokenInfo方法保存登录成功返回的token       
        //res.data.access是返回信息中token所在的字段名,如不知道请回顾上面Django中自定义返回信息里定义的token返回字段     
        this.$store.commit("mSetTokenInfo", res.data.access); 
        //登录成功后跳转Home页并将用户信息传至Home页 
        this.$router.push({ 
            name: "Home", 
            params: { 
                username: res.data.data.username, 
                department: res.data.data.department 
                } 
            }); 
      }) 
      .catch(error => { 
          //登录失败 
          console.log(error) 
       });

到这里就能在浏览器中按F12,Network中看到接口里的Request Headers中看到携带的token信息,Application中看到保存在本地的token。


image.jpeg

image.jpeg

4、登录成功并保存token后,后续的请求中携带保存的token一起向后端发送请求。

//后续记得用已经封装好的instance方法发起axios请求,别再用this.axios了!!!! 
instance.post("/home/yz_cookie", login_data).then(res => { 
    if (res.data.status === 200) { 
        //用户身份后端验证通过 """请求成功后业务逻辑""" 
    } else if (res.data.status === 401) { 
        //用户身份后端验证失败,前端重定向跳转至登录页面,重新登录 
        this.$router.push({ name: "Login" }); 
    } 
}); 
这里请求成功后端身份验证通过后, 再手动删除浏览器Local Storage中保存的token,再次请求,后端身份验证失败,前端重定向跳转用户登录页。

至此,Django+Vue,前后端分离,用户身份验证流程就走完了。

End~

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,015评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,262评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,727评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,986评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,363评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,610评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,871评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,582评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,297评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,551评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,053评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,385评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,035评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,079评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,841评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,648评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,550评论 2 270

推荐阅读更多精彩内容

  • 第一部分 Python基础篇(80题) 1、为什么学习Python? Python相对于其他编程语言有很多优点: ...
    清清子衿木子水心阅读 1,658评论 0 1
  • 为什么学习Python? 通过什么途径学习的Python? 上网收集视频,资料 关注公证号 买教程,书籍 Pyth...
    130920阅读 1,100评论 0 0
  • 1、谈谈对http协议的认识流程:1.域名解析域名解析检查顺序为:浏览器自身DNS缓存---》OS自身的DNS缓存...
    Zzmi阅读 594评论 0 0
  • 《Django Web典型模块开发实战》 一、Django组件 1、AOP(Aspect Oriented Pro...
    myofee阅读 298评论 1 1
  • Wordpress的坑 写在前面:这篇是给纯纯的新手看的,看完这篇建一个安全的自有站完全ok。 ​ ...
    muyu1900阅读 171评论 0 0