这篇博客记录一下如何实现一个简单的登录权限判断,由于入行时间不长,因此对权限相关知识的理解浅薄,如有幸被大佬看到,希望大佬不吝赐教。
实现简单的登录权限判断主要分四个步骤。
- 登录服务器端实现以及登录接口实现
- 登录获取token
- store与本地存储token
- 路由权限登录判断
接下来我将依次实现上述步骤。
1. 登录服务器端实现以及登录接口实现
要实现一个登录页面首先需要一个登录的请求接口,因此我们模拟服务器端发送一个axios请求。
这里我们准备了两个json格式的文件admin_login.json
和vip_login.json
。
admin_login.json
代码如下:
{
"code": 0,
"message": "登录成功",
"data": {
"token": "admin"
}
}
vip_login.json
代码如下:
{
"code": 0,
"message": "登录成功",
"data": {
"token": "vip"
}
}
如果登录请求url的user参数是amdin
,则响应admin_login.json
对应的json数据,否则响应vip_login.json
对应的json数据。注意,这里为了简化流程,并没有使用jwt实现动态的token。
有了响应数据,下面我们实现登录请求接口。
// 服务器端
const express = require("express");
const app = new express();
const vipLogin = require("./data/vip_login.json");
const adminLogin = require("./data/admin_login.json");
const url = require("url");
// 登录接口
app.get("/login", (req, res) => {
// 调用query可以使用query对象内的属性
const user = url.parse(req.url, true).query.user;
// 如果请求的url参数是admin,返回admin对应的json数据
if (user === "admin") {
res.send(adminLogin);
} else {
res.send(vipLogin);
}
});
app.listen(3000, () => {
console.log("服务器运行在http://localhost:3000");
});
这里涉及到url.parse(param1,param2)
方法,我们稍作讲解。
该方法可以解析url,可以把query参数解析成键值对形式的数值保存内容,param1
表示请求的url,param2
是布尔值,表示是否将query参数转成一个query对象,url.parse(param1,param2).query.属性名
可以获取请求url的参数的具体值。
2. 登录获取token
封装axios请求
// 用于封装axios
import axios from "axios";
import store from "@/store/index";
const http = {};
let instance = axios.create({
timeout: 5000,
// baseURL:"http://locahost:3000"
});
// 添加请求拦截器
instance.interceptors.request.use(function (config) {
// 请求头添加token
// if (store.state.UserToken) {
// config.header.Authorization = store.state.UserToken;
// }
return config;
},
function (error) {
return Promise.reject(error);
}
);
// 响应拦截器即异常处理
instance.interceptors.response.use((response) => {
return response.data;
},(err) => {
if (err && err.response) {
switch (err.response.status) {
case 400:
err.message = "请求出错";
break;
case 401:
Message.warning({
message: "授权失败,请重新登录",
});
store.commit("LOGIN_OUT");
setTimeout(() => {
window.location.reload();
}, 1000);
return;
case 403:
err.message = "拒绝访问";
break;
case 404:
err.message = "请求错误,未找到该资源";
break;
case 500:
err.message = "服务器端出错";
break;
}
} else {
err.message = "连接服务器失败";
}
Message.error({message: err.message});
return Promise.reject(err.response);
}
);
http.get = function (url, options) {
return new Promise((resolve, reject) => {
instance.get(url, options).then((response) => {
if (response.code === 0) {
resolve(response.data);
} else {
Message.error({ message: response.message,});
reject(response.message);
}
}).catch((e) => {console.log(e);});
});
};
定义登录接口
import axios from "../utils/http";
// 登录接口
export function login(user) {
return axios.get("/api/login?user=" + user);
}
跨域的处理方式
后台:cors
前台:proxy开发环境下配置代理 这里我们使用这种方式
修改vue.config.js
配置文件如下。
const { defineConfig } = require("@vue/cli-service");
module.exports = defineConfig({
transpileDependencies: true,
devServer: {
proxy: {
"/api": {
target: "http://localhost:3000",
changeOrigin: true,
pathRewrite: {
"^/api": "",
},
},
},
},
});
修改配置后,记得重启服务器。
下面我们实现一个简易的登录页面来验证是否能通过接口成功获取token。
login/index.vue
<template>
<div class="container">
<div class="login">
<div class="main">
<div class="account">
<span>账号:</span>
<input type="text" placeholder="随便输" name="account" v-model.trim="account" />
</div>
<div class="password">
<span>密码:</span>
<input type="password" placeholder="随便输" name="password" v-model.trim="password" @keyup.enter="login" />
</div>
<p class="loginBtn">
<button id="loginBtn" @click="login">登录</button>
</p>
</div>
</div>
</div>
</template>
<script>
import { login } from "../../api";
export default {
data() {
return {
account: "",
password: "",
};
},
mounted() {},
methods: {
async login() {
let data = await login(this.account);
let token = data.token;
console.log("当前token为:", token);
// this.$store.commit("LOGIN_IN", token);
// this.$router.replace("/");
},
},
};
</script>
<style scoped>
.container {
background-color: #2b4b6b;
width: 100%;
height: 100%;
}
.login {
width: 450px;
height: 300px;
background-color: #fff;
border-radius: 10px;
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
}
.main {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
}
</style>
可以看到成功获取token。
3. store与本地存储token
我们使用vuex实现保存token至本地缓存。
store/defaultState.js
export default {
get UserToken() {
return localStorage.getItem("token");
},
set UserToken(value) {
localStorage.setItem("token", value);
},
};
store/mutation.js
export default {
LOGIN_IN(state, token) {
state.UserToken = token;
},
LOGIN_OUT(state) {
state.UserToken = "";
},
};
store/index.js
import Vue from "vue";
import Vuex from "vuex";
import state from "./defaultState";
import mutations from "./mutations";
Vue.use(Vuex);
export default new Vuex.Store({
state,
mutations,
});
修改login/index.vue
的login方法如下:
methods: {
async login() {
let data = await login(this.account);
let token = data.token;
// console.log("当前token为:", token);
this.$store.commit("LOGIN_IN", token);
// this.$router.replace("/");
},
},
验证结果如下:
4. 路由权限登录判断
我们通过路由守卫实现权限判断。
实现路由守卫
import router from "./index";
import store from "@/store/index";
// 路由守卫
router.beforeEach((to, from, next) => {
if (!store.state.UserToken) {
// Usertoken不存在表示未登录=>页面是否需要登录
// to.matched该数组中保存着匹配到的所有路由信息
if (
to.matched.length > 0 &&
!to.matched.some((record) => record.meta.requiresAuth)
) {
// 如果路由信息数组存在,并且不存在需要登录后才能进入的路由时,跳转下一路由
next();
} else {
// 路由信息数组不存在或者 存在需要登录后此案进入的路由时,跳转登录页面路由
next({
path: "/login",
});
}
} else {
// 用户已经登录,处理路由的访问权限,跳转下一路由
next();
}
});
实现路由守卫的代码中涉及到to.matched()
方法,了解此方法可以参考以下博客。
修改login/index.vue
的login方法如下:
methods: {
async login() {
let data = await login(this.account);
let token = data.token;
// console.log("当前token为:", token);
this.$store.commit("LOGIN_IN", token);
this.$router.replace("/");
},
},
最后我们验证一下
小知识点总结:
- to.matched
- array.some