Django + drf-jwt 认证 + Vue3 使用 Axios
Axios的安装和配置安装pnpm install axios封装 axios:配置baseUrl,请求拦截,响应拦截// requests.ts 文件中// import { Message } from "element-ui";/****request.js****/// 导入axiosimport axios from "axios";// 使用element-ui Message做消息提
·
Axios的安装和配置
- 安装
pnpm install axios
- 封装 axios:配置baseUrl,请求拦截,响应拦截
// requests.ts 文件中
// import { Message } from "element-ui";
/**** request.js ****/
// 导入axios
import axios from "axios";
// 使用element-ui Message做消息提醒
//1. 创建新的axios实例,
const service = axios.create({
// 公共接口--这里注意后面会讲
baseURL: "http://127.0.0.1:8000/api/v1",
// 超时时间 单位是ms,这里设置了3s的超时时间
timeout: 3 * 1000,
});
// 2.请求拦截器
service.interceptors.request.use(
(config) => {
//发请求前做的一些处理,数据转化,配置请求头,设置token,设置loading等,根据需求去添加
// config.data = JSON.stringify(config.data); //数据转化,也可以使用qs转换
// config.headers = {
// "Content-Type": "application/x-www-form-urlencoded", //配置请求头
// };
//注意使用token的时候需要引入cookie方法或者用本地localStorage等方法,推荐js-cookie
const token = localStorage.getItem("token"); //这里取token之前,你肯定需要先拿到token,存一下
if (token) {
// config.params = { token: token }; //如果要求携带在参数中
config.headers = {
// 需要根据 DRF 提供的 JWT 认证来携带Token,前缀也可以是其它的
Authorization: "JWT " + token,
}; //如果要求携带在请求头中
}
console.log("查看请求头", config.headers);
return config;
},
(error) => {
return Promise.reject(error);
}
);
// 3.响应拦截器
service.interceptors.response.use(
(response) => {
//接收到响应数据并成功后的一些共有的处理,关闭loading等
return response;
},
(error) => {
/***** 接收到异常响应的处理开始 *****/
if (error && error.response) {
// 1.公共错误处理
// 2.根据响应码具体处理
switch (error.response.status) {
case 400:
error.message = "错误请求";
break;
case 401:
error.message = "未授权,请重新登录";
break;
case 403:
error.message = "拒绝访问";
break;
case 404:
error.message = "请求错误,未找到该资源";
window.location.href = "/NotFound";
break;
case 405:
error.message = "请求方法未允许";
break;
case 408:
error.message = "请求超时";
break;
case 500:
error.message = "服务器端出错";
break;
case 501:
error.message = "网络未实现";
break;
case 502:
error.message = "网络错误";
break;
case 503:
error.message = "服务不可用";
break;
case 504:
error.message = "网络超时";
break;
case 505:
error.message = "http版本不支持该请求";
break;
default:
error.message = `连接错误${error.response.status}`;
}
} else {
// 超时处理
if (JSON.stringify(error).includes("timeout")) {
console.log("服务器响应超时,请刷新当前页");
}
error.message = "连接服务器失败!";
}
// 可以配合Element-plus来提示相关信息
// ELMessage.error(error.message);
/***** 处理结束 *****/
//如果不需要错误处理,以上的处理过程都可省略
// return Promise.resolve(error.response);
console.log(error.message);
console.log(1213);
return Promise.reject(error);
}
);
//4.导入文件
export default service;
- ts 中简单的使用,get 和 post 请求
// api.ts
import service from "./requests";
// 按需导出每个 API
// *************************** //
// 请求首页数据
interface Iget {
[propName: string]: any;
}
export function GetHomeAPI<T>(data: Iget) {
return service.get<T>("/mdm/slideinfo/", {
params: data,
});
}
interface ILogin {
username: string;
password: string;
}
export function PostLoginAPI(data: ILogin) {
return service({
method: "POST",
url: "/user/login/auth/",
data,
});
}
Vue中使用
<script setup lang="ts">
// 导入 API 接口数据
import { GetHomeAPI, PostLoginAPI } from './api/api'
interface IgetHome {
"id": number;
"province": string;
"county": string;
"slide_name": string;
"slide_head": string;
"slide_type": string;
"slide_status": number;
"created_time": string;
"is_active": boolean;
"user": number;
}
interface Ilogin {
"token": string
"id": number
"username": string
"role": boolean
}
function getHome() {
GetHomeAPI<IgetHome>({}).then(
(res) => {
console.log(res)
}
).catch()
}
const getAs = async () => {
await GetHomeAPI({ id: 1 }).then(
(res) => {
console.log(res.data)
}
).catch()
}
const login = () => {
PostLoginAPI({
username: "admin",
password: "521",
}).then(
(res) => {
console.log(res.data)
localStorage.setItem("token", res.data.token)
}
).catch()
}
</script>
<template>
<button @click="getHome">getHome</button>
<button @click="getAs">getAs</button>
<button @click="login">login</button>
</template>
<style>
</style>
Django后端配置
# settings.py
# 针对 drf 的配置信息, 全局配置 drf的视图的认证和权限
REST_FRAMEWORK = {
# 指定视图权限
'DEFAULT_PERMISSION_CLASSES': (
# 'rest_framework.permissions.AllowAny', # 默认每个视图,允许任何用户访问
# 'rest_framework.permissions.IsAuthenticatedOrReadOnly', # 认证用户可操作,否则只能访问
'rest_framework.permissions.IsAuthenticated', # 认证用户可操作,否则只能访问
), # 也可以在每个视图中指明权限类
# 指定drf认证机制
'DEFAULT_AUTHENTICATION_CLASSES': (
# rest_framework_jwt认证, 也可以在每个视图中指明认证类
'rest_framework_jwt.authentication.JSONWebTokenAuthentication',
),
# 新版drf schema_class默认用的是rest_framework.schemas.openapi.AutoSchema
'DEFAULT_SCHEMA_CLASS': 'rest_framework.schemas.coreapi.AutoSchema',
}
# 全局配置 drf的视图的限流Throttling
# REST_FRAMEWORK = {
# 'DEFAULT_THROTTLE_CLASSES': (
# # 限制所有匿名未认证用户,使用IP区分用户
# 'rest_framework.throttling.AnonRateThrottle',
# # 限制认证用户,使用User id 来区分
# 'rest_framework.throttling.UserRateThrottle'
# ),
# 'DEFAULT_THROTTLE_RATES': {
# # 可以使用 second, minute, hour 或day来指明周期
# 'anon': '3/minute',
# 'user': '5/minute'
# }
# }
# 针对 rest_framework_jwt 的配置信息
JWT_AUTH = {
'JWT_AUTH_HEADER_PREFIX': 'JWT', # 设置 请求头中的前缀
'JWT_RESPONSE_PAYLOAD_HANDLER':
# 'rest_framework_jwt.utils.jwt_response_payload_handler', # 默认jwt认证成功返回数据
'user.utils.jwt_response_payload_handler', # 自定义jwt认证成功返回数据
'JWT_EXPIRATION_DELTA': datetime.timedelta(seconds=60 * 60 * 3), # 指明token的有效期, 默认5分
'JWT_ALLOW_REFRESH': True, # 允许刷新
'JWT_REFRESH_EXPIRATION_DELTA': datetime.timedelta(
days=7
), # 在多久间隔内可以用旧token来刷新以便获取新的token,默认是7天
}
验证
- 未登录
- 登录前,没有token等
- 登录后,保存了token
- 登录后,再请求数据
结合pinia来使用
- 更改请求拦截
import { ElMessage } from 'element-plus';
// 导入axios
import axios from 'axios';
import { IUser, KEY_USER_ID } from '@/store/modules/useUserStore';
// 使用element-ui Message做消息提醒
//1. 创建新的axios实例,
const service = axios.create({
// 公共接口--这里注意后面会讲
baseURL: 'http://127.0.0.1:8000/api/v1',
// 超时时间 单位是ms,这里设置了5s的超时时间
timeout: 5 * 1000,
});
// 2.请求拦截器
service.interceptors.request.use(
(config) => {
//发请求前做的一些处理,数据转化,配置请求头,设置token,设置loading等,根据需求去添加
// config.data = JSON.stringify(config.data); //数据转化,也可以使用qs转换
// config.headers = {
// "Content-Type": "application/x-www-form-urlencoded", //配置请求头
// };
//注意使用token的时候需要引入cookie方法或者用本地localStorage等方法,推荐js-cookie
//这里取token之前,你肯定需要先拿到token,存一下
try {
const user = JSON.parse(localStorage.getItem(KEY_USER_ID) || '') as IUser;
if (user.token) {
config.headers!['Authorization'] = `JWT ${user.token}`;
}
} catch (e) {}
// if (token) {
// // config.params = { token: token }; //如果要求携带在参数中
// config.headers = {
// // 需要根据 DRF 提供的 JWT 认证来携带Token,前缀也可以是其它的
// Authorization: 'JWT ' + token.token,
// }; //如果要求携带在请求头中
// }
// console.log('查看请求头', config.headers);
return config;
},
(error) => {
return Promise.reject(error);
}
);
// 3.响应拦截器
service.interceptors.response.use(
(response) => {
//接收到响应数据并成功后的一些共有的处理,关闭loading等
return response;
},
(error) => {
/***** 接收到异常响应的处理开始 *****/
if (error && error.response) {
// 1.公共错误处理
// 2.根据响应码具体处理
switch (error.response.status) {
case 400:
error.message = '错误请求!';
break;
case 401:
error.message = '未授权,请重新登录';
break;
case 403:
error.message = '拒绝访问';
break;
case 404:
error.message = '请求错误,未找到该资源';
window.location.href = '/NotFound';
break;
case 405:
error.message = '请求方法未允许';
break;
case 408:
error.message = '请求超时';
break;
case 500:
error.message = '服务器端出错';
break;
case 501:
error.message = '网络未实现';
break;
case 502:
error.message = '网络错误';
break;
case 503:
error.message = '服务不可用';
break;
case 504:
error.message = '网络超时';
break;
case 505:
error.message = 'http版本不支持该请求';
break;
default:
error.message = `连接错误${error.response.status}`;
}
} else {
// 超时处理
if (JSON.stringify(error).includes('timeout')) {
console.log('服务器响应超时,请刷新当前页');
}
error.message = '连接服务器失败!';
}
// 可以配合Element-plus来提示相关信息
ElMessage.error(error.message);
/***** 处理结束 *****/
//如果不需要错误处理,以上的处理过程都可省略
// return Promise.resolve(error.response);
return Promise.reject(error);
}
);
//4.导出文件
export default service;
- pinia中
import { defineStore } from 'pinia';
// 根据自己返回数据来定义接口
export interface IUser {
id: number;
username: string;
token: string;
role: string;
email?: string;
}
export const KEY_USER_ID = 'user';
const useUserStore = defineStore({
id: KEY_USER_ID,
state: (): IUser => ({
id: -1,
username: '',
role: '',
email: '',
token: '',
}),
actions: {
setToken(token: string) {
this.$state.token = token;
},
setID(id: number) {
this.$state.id = id;
},
setRole(role: string) {
this.$state.role = role;
},
// 将接口规范全变为可选项
login(user: Partial<IUser>) {
this.$state = {
...this.$state,
...user,
};
},
},
// 开启数据缓存至浏览器
persist: {
enabled: true,
strategies: [
{
// 自定义名称
key: KEY_USER_ID,
// 保存位置,默认保存在sessionStorage
storage: localStorage,
// 指定要持久化的数据
// paths: ['age'],
},
],
},
});
export default useUserStore;
- 登录函数中
import useUserStore from '@/store/modules/useUserStore';
import { useRouter } from 'vue-router';
const router = useRouter()
const useUser = useUserStore()
const login = () => {
PostLoginAPI({
username: "admin",
password: "521",
}).then(
(res) => {
console.log(res.data)
// localStorage.setItem("token", res.data.token)更改如下
useUser.login(res.data)
}
).catch()
}
更多推荐
已为社区贡献5条内容
所有评论(0)