首先感谢RouYi框架提供的一些思路及参考代码,向RuoYi大佬致敬!
Tips:阅读本文前,先了解一下cookie,vue,encrypt,路由拦截等一些基础知识,有了这些知识的沉淀,下面的理解起来会更简单一些。
我们在着手登录页的设计时,需要考虑到登录验证,token存储以及token过期相应操作,encrypt密码加密,路由拦截,登录权限管理等等,有了一个大概的思路,才能进行代码的编写,否则就像我刚开始那样bug连篇,后期不断的填坑🙄,浪费时间浪费精力。所以为了避免大家走弯路,本文对登录操作做一个详细的介绍。
注:1、本文只对Rouyi框架前端登录操作的思路介绍,涉及到相关的后端操作需自行学习;
2、主要使用的框架及工具:vue2+vuex+vue-router+ElementUi;
3、关于本文用到的相关依赖包及其版本也会在对应模块分别作注释;
4、本文只是一些个人拙见,如若有不妥之处或疑惑,还希望各位大佬在评论区批评指正,切勿引战`(*>﹏<*)′
一、流程图
首先说下登录的思路:
大概的流程就是这样,其中还包含用户权限判断暂时未添加进去。
二、实现方法
1.先介绍一下关于Cookie管理token的封装
这里借助的依赖包是js-cookie版本^3.0.1 在utils目录下新建auth.js文件,实现获取、添加、删除token三个方法,具体代码如下
import Cookies from "js-cookie";
const TokenKey = "MyToken";
export function getToken() {
return Cookies.get(TokenKey);
}
export function setToken(token) {
return Cookies.set(TokenKey, token);
}
export function removeToken() {
return Cookies.remove(TokenKey);
}
2.登录接口api模块的封装以及vuex的user模块管理
1.api模块的封装
这里采用的是axios请求接口,关于axios接口封装后期会出一期教程。主要是对验证码的请求以及登录登出的验证请求
// request模块封装这里未给出!!!
// 登录方法
export function login(username, password, code, uuid) {
const data = {
username,
password,
code,
uuid
};
return request({
url: "/login",
headers: {
isToken: false
},
method: "post",
data: data
});
}
// 退出方法
export function logout() {
return request({
url: "/logout",
method: "post"
});
}
// 获取验证码
export function getCodeImg() {
return request({
url: "/captchaImage",
headers: {
isToken: false
},
method: "get",
timeout: 20000
});
}
2.vuex的user模块管理
vuex版本是^3.6.2,在src下新建store文件夹并在其下新建index.js和modules文件夹,在modules文件夹下新建user.js模块,不要忘记在main.js中引入store哦!
user模块主要是负责管理用户登录登出,记住密码的操作
main.js
import Vue from "vue";
...
import store from "./store";
...
new Vue({
store,
render: h => h(App)
}).$mount("#app");
index.js
import Vue from "vue";
import Vuex from "vuex";
import user from "./modules/user.js";
Vue.use(Vuex);
export default new Vuex.Store({
modules: {
user,
},
});
user.js
import { login, logout } from "@/api/login/login.js";
import { getToken, setToken, removeToken } from "@/utils/auth";
import { Message } from "element-ui";
const user = {
state: {
token: getToken(),
name: "",
permissions: []
},
mutations: {
SET_TOKEN: (state, token) => {
state.token = token;
},
SET_NAME: (state, name) => {
state.name = name;
},
SET_PERMISSIONS: (state, permissions) => {
state.permissions = permissions;
}
},
actions: {
// 登录
Login({ commit }, userInfo) {
const username = userInfo.username.trim();
const password = userInfo.password;
const code = userInfo.code;
const uuid = userInfo.uuid;
return new Promise((resolve, reject) => {
login(username, password, code, uuid)
.then(res => {
if (res.code === 200) {
setToken(res.token);
commit("SET_TOKEN", res.token);
resolve();
} else {
Message.error(res.msg);
return;
}
})
.catch(error => {
reject(error);
});
});
},
// 退出系统
LogOut({ commit, state }) {
return new Promise((resolve, reject) => {
commit("SET_TOKEN", "");
commit("SET_PERMISSIONS", []);
removeToken();
resolve();
});
},
// 前端 登出
FedLogOut({ commit }) {
return new Promise(resolve => {
commit("SET_TOKEN", "");
removeToken();
resolve();
});
}
}
};
export default user;
3.验证输入框是否为空
先在data()中建立对象
loginForm: {
username: "QDTG",
password: "",
rememberMe: true,
code: "",
uuid: ""
},
在模板的input标签中双向数据绑定v-model="loginForm"
验证方法主要是判断input中的数据是否为空方法如下
validate() {
// 验证输入框是否存在空
if (
this.loginForm.code == undefined ||
this.loginForm.username === undefined ||
this.loginForm.password === undefined
) {
Message.error("请输入账号、密码、验证码!");
return false;
} else {
return true;
}
},
4.验证账号密码是否正确,并对密码加密存储在cookie中
如果登录勾选了记住密码操作则将密码通过encrypt加密保存在cookie中
加密模块依赖
"jsencrypt": "3.0.0-rc.1",
/utils/jsencrypt.js
import JSEncrypt from "jsencrypt/bin/jsencrypt.min";
// 密钥对生成 http://web.chacuo.net/netrsakeypair
const publicKey =
"根据网站生成的公钥钥填入" +
"根据网站生成的公钥钥填入";
const privateKey =
"根据网站生成的私钥填入";
// 加密
export function encrypt(txt) {
const encryptor = new JSEncrypt();
encryptor.setPublicKey(publicKey); // 设置公钥
return encryptor.encrypt(txt); // 对数据进行加密
}
// 解密
export function decrypt(txt) {
const encryptor = new JSEncrypt();
encryptor.setPrivateKey(privateKey); // 设置私钥
return encryptor.decrypt(txt); // 对数据进行解密
}
/components/Login.vue
handleLogin() {
if (this.validate()) {
this.loading = true;
// 是否记住密码
Cookies.set("username", this.loginForm.username, { expires: 30 });
Cookies.set("password", encrypt(this.loginForm.password), {
expires: 30
});
Cookies.set("rememberMe", this.loginForm.rememberMe, {
expires: 30
});
this.$store
.dispatch("Login", this.loginForm)
.then(() => {
this.$router.push({ path: "/home" }).catch(() => {});
})
.catch(() => {
this.loading = false;
if (this.captchaOnOff) {
this.getCode();
}
});
}
}
5. 路由拦截
在src下新建premission.js,并在main.js中引入。该模块是为了给登录操作进行路由拦截,如果用户未登录或登录信息过期,则不允许用户进入页面,或者添加页面白名单,在白名单内的页面允许未登录状态下进入,其他一律跳转到登录页面。
// main.js
// 登录验证
import "./permission"; // permission control
permission.js
import router from "./router";
import store from "./store";
import { Message } from "element-ui";
import { getToken } from "@/utils/auth";
import { isRelogin } from "@/utils/request";
const whiteList = ["/login"];
router.beforeEach((to, from, next) => {
if (getToken()) {
/* has token*/
if (to.path === "/login") {
next({ path: "/home" });
} else {
next();
}
} else {
// 没有token
if (whiteList.indexOf(to.path) !== -1) {
// 在免登录白名单,直接进入
next();
} else {
next(`/login?redirect=${to.fullPath}`); // 否则全部重定向到登录页
}
}
});
router.afterEach(() => {});
到此一个简单的登录就大致完成了,希望该教程能够帮到各位,喜欢的小伙伴来个点赞关注收藏吧!非常感谢!