JWT

在用户注册或登录后,我们想记录用户的登录状态,或者为用户创建身份认证的凭证。

我们不再使用Session认证机制,而使用Json Web Token认证机制。

Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC 7519).

该token被设计为紧凑且安全的,特别适用于分布式站点的单点登录(SSO)场景。

JWT的声明一般被用来在身份提供者和服务提供者间传递被认证的用户身份信息,以便于从资源服务器获取资源,

也可以增加一些额外的其它业务逻辑所必须的声明信息,该token也可直接被用于认证,也可被加密。

安装配置JWT

pip install djangorestframework-jwt

配置

项目settings中配置

# drf框架的配置信息
REST_FRAMEWORK = {
# 异常处理
'EXCEPTION_HANDLER': 'luffy.utils.exceptions.custom_exception_handler',
# 用户登陆认证方式
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework_jwt.authentication.JSONWebTokenAuthentication',
'rest_framework.authentication.SessionAuthentication',
'rest_framework.authentication.BasicAuthentication'
,
),

}
# jwt载荷中的有效期设置
JWT_AUTH = {
'JWT_EXPIRATION_DELTA': datetime.timedelta(days=1), # 有效期设置
'JWT_RESPONSE_PAYLOAD_HANDLER': 'users.utils.jwt_response_payload_handler',
}
  • JWT_EXPIRATION_DELTA 指明token的有效期

JWt使用

Django REST framework JWT 扩展的说明文档中提供了手动签发JWT的方法.

from rest_framework_jwt.settings import api_settings

jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER payload = jwt_payload_handler(user)
token = jwt_encode_handler(payload)

在用户注册或登录成功后,在序列化器中返回用户信息以后同时返回token即可。

默认情况下,djangorestframework-jwt这个模块已经内置了一个登陆视图接口给我们了。我们直接使用

当前users的urls.py文件代码:

from django.urls import path
# jwt内部实现的登陆视图
from rest_framework_jwt.views import obtain_jwt_token
urlpatterns=[
path(r"login", obtain_jwt_token ),
]

在总路由文件中,urls.py中注册子应用路由:

path('users/',include('users.urls')) ,

可以通过postman来完成测试:

输入账号和密码时:

经过上面的测试,登陆视图已经完成了。

jwt后端认证

Django REST framework JWT提供了登录签发JWT的视图,可以直接使用.

1. users应用中urls.py :

from rest_framework_jwt.views import obtain_jwt_token

urlpatterns = [
path(r'login/$', obtain_jwt_token),
]

2.

但是默认的返回值仅有token,我们还需在返回值中增加username和user_id。

通过修改该视图的返回值可以完成我们的需求。

在users应用中新建一个utils.py 文件,在users/utils.py 中,创建:

def jwt_response_payload_handler(token, user=None, request=None):
"""
自定义jwt认证成功返回数据
:token 返回的jwt
:user 当前登录的用户信息[对象]
:request 当前本次客户端提交过来的数据
"""
return {
'token': token,
'id': user.id,
'username': user.username,
}

3. 项目配置文件中:

# JWT
JWT_AUTH = {
'JWT_EXPIRATION_DELTA': datetime.timedelta(days=1),
'JWT_RESPONSE_PAYLOAD_HANDLER': 'users.utils.jwt_response_payload_handler',
}

测试结果:

前端登录功能的实现

Login.vue登陆视图组件,代码:

<button class="login_btn" @click="loginhander">登录</button>
<script>
export default {
name: "Login",
data() {
return {
remmber:false,//是否记住密码
login_type: ,//登录方式,短信登录还是密码登录
username: "",// 登录账号
password: "",// 登录密码
mobile: "",//手机号码
sms: "",// 手机短信验证码
}
},
methods:{
loginheader:function () {
//登录函数
this.$axios.post('http://127.0.0.1:8000/users/login',{
'username':this.username,
'password':this.password},{responseType:'json'}
).then(
response=>{
//请求成功,保存登录状态
console.log(response); } ).catch(error=>{})
}
},
components: {}, }
</script>

点击登录按钮的情况:

当用户名和密码正确时,就需要将服务端返回的数据进行保存。

前端保存jwt

我们可以将JWT保存在cookie中,也可以保存在浏览器的本地存储里,我们保存在浏览器本地存储中

浏览器的本地存储提供了sessionStorage 和 localStorage 两种:

  • sessionStorage 会话存储,浏览器关闭即失效

  • localStorage 永久存储,长期有效

使用方法:

sessionStorage.变量名 = 变量值   // 保存数据
sessionStorage.变量名 // 读取数据
sessionStorage.clear() // 清除所有sessionStorage保存的数据 localStorage.变量名 = 变量值 // 保存数据
localStorage.变量名 // 读取数据
localStorage.clear() // 清除所有localStorage保存的数据

在端登录后保存用户登录信息和登录成功后的页面跳转:

在Login.vue:

<div class="rember">
<p>
<input type="checkbox" class="no" name="a" v-model="remmber" ></input>
<span>记住密码</span>
</p>
<p>忘记密码</p>
</div>
<script>
export default {
name: "Login",
data() {
return {
remmber:false,//是否记住密码
login_type: 1,//登录方式,短信登录还是密码登录
username: "",// 登录账号
password: "",// 登录密码
mobile: "",//手机号码
sms: "",// 手机短信验证码
}
},
methods:{
loginheader:function () {
//登录函数
this.$axios.post('http://127.0.0.1:8000/users/login',{
'username':this.username,
'password':this.password},{responseType:'json'}
).then(
response=>{
//请求成功,保存登录状态
console.log(response);
//当要记住密码时:
if (this.remmber){
// 记住密码时
let data = response.data;
localStorage.token=data.token;
localStorage.id=data.id;
localStorage.username=data.username;
}else {
//不记住密码
localStorage.removeItem('token');
let data = response.data;
sessionStorage.token=data.token;
sessionStorage.id=data.id;
sessionStorage.username=data.username;
}
//登录成功之后跳转页面
this.$router.go(-1);// 跳转到之前的访问页面
// this.$router.push('/home') // 或者跳转到首页
} ).catch(error=>{
console.log(error)
})
}
},
components: {}, }
</script>

未登录时:

登录成功后:

在header.vue组件中:

<script>
export default {
name:"Header",
props:["current_page"],
data(){
return {
is_login: false, /* 是否登录 */
token:localStorage.token || sessionStorage.token,
}
},
created:function () {
//登录状态判断
if(this.token){
//登录成功
this.is_login=true;
}else {
this.is_login=false;
}
},
methods:{
logout(){
localStorage.clear();
sessionStorage.clear();
this.is_login=false;
alert("退出登录成功!"
)
}

} }
</script>
<template>
<div class="header">
<el-container>
<el-header height="80px">
<el-row>
<el-col class="logo" :span="3">
<router-link to="/"><img src="../../assets/head-logo.svg" alt=""></router-link>
</el-col>
<el-col :span="16">
<!-- gutter每一列之间的间隔空隙 -->
<el-row class="nav" :gutter="20">
<el-col :span="3"><router-link :class="current_page==1?'active':''" to="/courses">免费课</router-link></el-col>
<el-col :span="3"><router-link :class="current_page==2?'active':''" to="/courses">轻课</router-link></el-col>
<el-col :span="3"><router-link :class="current_page==3?'active':''" to="/courses">学位课</router-link></el-col>
<el-col :span="3"><router-link :class="current_page==4?'active':''" to="/courses">题库</router-link></el-col>
<el-col :span="3"><router-link :class="current_page==5?'active':''" to="/courses">教育</router-link></el-col>
</el-row>
</el-col>
<el-col v-if="is_login" class="login-bar" :span="5">
<div class="cart-ico">
<b></b>
<img src="../../assets/cart.svg" alt="">
<span>购物车</span>
</div>
<div class="study">学习中心</div>
<div class="member">
<el-dropdown>
<span class="el-dropdown-link">
<img src="../../assets/logo@2x.png" alt="">
</span>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item>我的账户 <i class="el-icon-arrow-right"></i></el-dropdown-item>
<el-dropdown-item>我的账户 <i class="el-icon-arrow-right"></i></el-dropdown-item>
<el-dropdown-item>我的账户 <i class="el-icon-arrow-right"></i></el-dropdown-item>
<el-dropdown-item><span @click="logout">退出登录</span> <i class="el-icon-arrow-right"></i></el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</div>
</el-col>
<el-col v-else class="login-bar" :span="5">
<div class="cart-ico">
<img src="../../assets/cart.svg" alt="">
<span>购物车</span>
</div>
<span class="header-login"><router-link to="/login">登录</router-link></span>
&nbsp;&nbsp;|&nbsp;&nbsp;
<span class="header-register">注册</span>
</el-col>
</el-row>
</el-header>
</el-container>
</div>
</template> <script>
export default {
name:"Header",
props:["current_page"],
data(){
return {
is_login: false, /* 是否登录 */
token:localStorage.token || sessionStorage.token,
}
},
created:function () {
//登录状态判断
if(this.token){
//登录成功
this.is_login=true;
}else {
this.is_login=false;
}
},
methods:{
logout(){
localStorage.clear();
sessionStorage.clear();
this.is_login=false;
alert("退出登录成功!")
}
} }
</script> <style scoped>
.header{
width: 100%;
height: 80px;
background: #fff;
position: fixed;
left: 0;
top: 0;
margin: 0 auto;
z-index: 7;
text-overflow: ellipsis;
white-space: nowrap;
box-shadow: 0 0.5px 0.5px 0 #c9c9c9;
}
.el-container{
width: 1200px;
margin: 0 auto;
}
.el-header{
padding: 0;
}
.el-row,.el-col{
height: 80px;
}
.logo{
width: 118px;
}
.logo,.nav{
line-height: 80px;
}
.logo img{
vertical-align: middle; /* 设置图片垂直居中 */
}
.nav{
margin-left: 30px!important;
margin-right: 0!important;
}
.nav .el-col .active{
padding-bottom: 16px;
padding-left: 5px;
padding-right: 5px;
border-bottom: 4px solid #ffc210;
}
.nav,.study{
text-align: center;
color: #4a4a4a;
}
.nav .el-col:hover,.nav .el-col a:hover,.study:hover,.study a:hover{
color: #000000;
}
.login-bar{
display: flex;
align-items: center;
}
.cart-ico{
width: 88px;
height: 28px;
margin-right: 20px;
background: #f7f7f7;
border-radius: 17px;
display: flex;
align-items: center;
justify-content: space-around;
cursor: pointer;
position: relative;
font-size: 14px;
}
.cart-ico b{
width: 16px;
height: 16px;
line-height: 17px;
font-size: 12px;
color: #fff;
text-align: center;
background: #fa6240;
border-radius: 50%;
transform: scale(.8);
position: absolute;
left: 16px;
top: -1px;
}
.cart-ico img{
width: 15px;
height: auto;
margin-left: 6px;
}
.cart-ico span{
margin-right: 6px;
}
.study{
padding-left: 0;
font-family: PingFangSC-Regular;
letter-spacing: 0;
margin-right: 20px;
font-size: 15px;
cursor: pointer;
}
.member img{
width: 26px;
height: 26px;
border-radius: 50%;
display: inline-block;
cursor: pointer;
vertical-align: middle;
}
.member img:hover{
border: 1px solid rgb(255, 194, 16);
}
.el-dropdown-menu{
left: 1130px!important;
width: 180px;
top: 64px!important;
}
.el-dropdown-menu i{
float:right;
line-height: 36px;
}
.header-login,.header-register{
cursor: pointer;
font-size: 15px;
color: #4a4a4a;
}
.header-login:hover,.header-register:hover{
color: #000000;
}
</style>

header.vue

6 Django REST framework JWT 和登录功能实现的更多相关文章

  1. Django REST Framework JWT提供的登录签发的视图

    Django REST Framework JWT提供了一个视图.在我们登录的时候,会校验用户名.密码是否正确.如果信息无误,可以返回一个JWT token.就可以简单地实现了记录用户登录状态. 用法 ...

  2. Django REST framework JWT学习

    1.JWT学习 在用户注册或登录后,我们想记录用户的登录状态,或者为用户创建身份认证的凭证.我们不再使用Session认证机制,而使用Json Web Token认证机制. Json web toke ...

  3. Django REST Framework JWT 用户的登录注册

    安装配配置 pip install djangorestframework-jwt 配置setting ########### 1.在INSTALLED_APPS中加入'rest_framework. ...

  4. JWT验证机制【刘新宇】【Django REST framework中使用JWT】

    JWT 在用户注册或登录后,我们想记录用户的登录状态,或者为用户创建身份认证的凭证.我们不再使用Session认证机制,而使用Json Web Token认证机制. 什么是JWT Json web t ...

  5. Django REST framework+Vue 打造生鲜超市(一)

    一.项目介绍 1.1.掌握的技术 Vue + Django Rest Framework 前后端分离技术 彻底玩转restful api 开发流程 Django Rest Framework 的功能实 ...

  6. python 全栈开发,Day94(Promise,箭头函数,Django REST framework,生成json数据三种方式,serializers,Postman使用,外部python脚本调用django)

    昨日内容回顾 1. 内容回顾 1. VueX VueX分三部分 1. state 2. mutations 3. actions 存放数据 修改数据的唯一方式 异步操作 修改state中数据的步骤: ...

  7. Django REST Framework应用

    一. 什么是RESTful REST与技术无关,代表的是一种软件架构风格,REST是Representational State Transfer的简称,中文翻译为“表征状态转移” REST从资源的角 ...

  8. 1- vue django restful framework 打造生鲜超市

    Vue+Django REST framework实战 使用Python3.6与Django2.0.2(Django-rest-framework)以及前端vue开发的前后端分离的商城网站 项目支持支 ...

  9. Django Rest framework实现流程

    目录 一 什么是restful架构 二 Django REST framework简介 三 Django REST framework原理 四 Django REST framework源码流程 五 ...

随机推荐

  1. bzoj1566: [NOI2009]管道取珠 DP

    题目链接 https://www.lydsy.com/JudgeOnline/problem.php?id=1566 思路 n个球,第i个球颜色为ai,对于颜色j,对答案的贡献为颜色为j的球的个数的平 ...

  2. 【学习】Hall’s Marriage Theorem

    其实是在做题时遇到这个定理的. 这个定理的图论意义是: 对于一个二分图\(G=\{X+Y,E\}\),它满足: \(\forall W \subseteq X, \, |W| \leq |N_G(W) ...

  3. Win32汇编学习(1):基本概念

    背景知识 Windows 把每一个 Win32 应用程序放到分开的虚拟地址空间中去运行,也就是说每一个应用程序都拥有其相互独立的 4GB 地址空间,当然这倒不是说它们都拥有 4GB 的物理地址空间,而 ...

  4. 牛客OI周赛7-普及组 解题报告

    出题人好评. 评测机差评. A 救救喵咪 二位偏序.如果数据范围大的话直接树状数组,不过才1000就\(O(n^2)\)暴力就ok了. #include <bits/stdc++.h> s ...

  5. 4-Three-Matterhorn man

    What was the main objective of early mountain climbers?   ①Modern alpinists try to climb mountains b ...

  6. facebook api call——error

    Error Codes send-api error-codes whatsapp api errors marketing-api error-reference graph-api/using-g ...

  7. Tag Helpers in forms in ASP.NET Core

    Tag Helpers in ASP.NET Core Tag Helpers in forms in ASP.NET Core HTML Form element ASP.NET Core buil ...

  8. Transaction2

    5. 事务状态 TransactionInformation 上面讲解过事务分为本地事务与分布式事务,而Transaction类的TransactionInformation是事务状态的记录,它可以跟 ...

  9. eclipse中建geoserver源码

    概述:本文讲述的是在eclipse中如何构建geoserver源码工程,其中涉及到了jdk,github,marven等. 1.安装git 从(http://git-scm.com/download/ ...

  10. Java处理微信公众号文章图片不显示微信

    http://blog.csdn.net/just4you/article/details/52933620