K8s 管理系统项目[前端部分–登录和登出]
1. 登录登出流程
1.1 登录流程
登入流程总的分为5步:
- 账号密码验证
- token生成
- token验证
- 验证成功进行跳转
- 验证失败返回/login
1.2 登出流程
登出流程就相对简单,分为2步
- 删除Token
- 跳转/login
2. 登录代码
src/views/login/Login.vue
这个页面纠结了很久,主要是因为vue-cli从4到5后polyfills不再被包含造成一系报错.不得不放弃jwt改用md5实现.
还有个就是加密的话,如果jwt可以用加盐的方式进行加密.
md5原生只能通过特定的进行加密并比较.想了下单纯用用户名做token的md5加密每次进去都会是一样的.需要手工加个盐,那么就把登录时间作为盐,进行加密和验证.
当然这里只是个演示环境用的方法太简单了.生产中肯定不会这么用.或者小伙伴有更好的方法也请留言.
另外这里为了美观,添加了一个图片,如果不喜欢可以注释掉98行
<template>
<div class="login">
<!-- 用户登录卡片 -->
<el-card class="login-card">
<template #header>
<div class="login-card-header">
<span>用户登录</span>
</div>
</template>
<!-- 表单 -->
<el-form :model="loginData" :rules="loginDataRules" ref="loginData">
<el-form-item prop="username">
<!-- 用户名 -->
<el-input prefix-icon="UserFilled" v-model.trim="loginData.username" maxlength="32" placeholder="请输入账号" clearable></el-input>
</el-form-item>
<el-form-item prop="password">
<!-- 密码 -->
<el-input prefix-icon="Lock" v-model.trim="loginData.password" maxlength="16" show-password placeholder="请输入密码" clearable></el-input>
</el-form-item>
<el-form-item>
<!-- 登录按钮 -->
<el-button type="primary" style="width: 100%;border-radius: 2px" :loading="loginLoading" @click="handleLogin">登 录</el-button>
</el-form-item>
</el-form>
</el-card>
</div>
</template>
<script>
import common from "../common/Config";
import httpClient from '../../utils/request';
import moment from 'moment';
import md5 from 'md5';
export default{
data() {
return {
//加载等待动画
loginLoading: false,
//登录验证的后端接口
loginUrl: common.loginAuth,
loginData: {
username: '',
password: ''
},
//校验规则
loginDataRules: {
username: [{
required: true,
message: '请填写用户名',
trigger: 'change'
}],
password: [{
required: true,
message: '请填写密码',
trigger: 'change'
}],
}
}
},
methods: {
//登录方法
handleLogin() {
httpClient.post(this.loginUrl, this.loginData)
.then(res => {
//账号密码校验成功后的一系列操作
localStorage.setItem('username', this.loginData.username);
localStorage.setItem('loginDate', moment().format('YYYY-MM-DD_HH:mm:ss'));
const salt = localStorage.getItem('username')+localStorage.getItem('loginDate')
//生成token
const tokenExpireTime = new Date(Date.now() + 24 * 60 * 60 * 1000); // 过期时间,24小时后
// const token = jwt.sign(this.loginData.username, 'test', options);
const token = md5(salt);
localStorage.setItem('token', token); // 将Token保存到localStorage中
localStorage.setItem('tokenExpireTime', tokenExpireTime.getTime().toString()); // 将过期时间保存到localStorage中
//跳转至根路径
this.$router.push('/');
this.$message.success({
message: res.msg
})
})
.catch(res => {
this.$message.error({
message: res.msg
})
})
}
}
}
</script>
<style scoped>
.login {
position: absolute;
width: 100%;
height: 100%;
background: aquamarine;
background-image: url(../../assets/img/login.png);
background-size: 100%;
}
.login-card {
position: absolute;
left: 70%;
top: 15%;
width: 350px;
border-radius: 5px;
background: rgb(255, 255, 255);
overflow: hidden;
}
.login-card-header {
text-align: center;
}
</style>
3. 登录页路由
2.1 login页面
src/router/index.js
{
path: '/login', //url路径
component: () => import('@/views/login/Login.vue'), //视图组件
meta: {title: "登录", requireAuth: false}, //meta元信息
}
2.2 拦截器
这里去验证是否有token和token是否过期.如果过期了就跳转到/login页面
// 导入md5
import md5 from 'md5';
//路由守卫,路由拦截
router.beforeEach((to, from, next) => {
//启动进度条
NProgress.start()
//设置头部
if (to.meta.title) {
document.title = to.meta.title
} else {
document.title = "Kubernetes"
}
// 放行
if (window.location.pathname == '/login') {
next()
}else{
// 获取localStorage中保存的Token和过期时间
const storedToken = localStorage.getItem('token');
const storedTokenExpireTime = localStorage.getItem('tokenExpireTime');
// 如果没有保存Token或过期时间,或者Token已经过期,则跳转到登录页面
if (!storedToken || !storedTokenExpireTime || Date.now() > parseInt(storedTokenExpireTime)) {
// 删除localStorage中保存的Token和过期时间
localStorage.removeItem('token');
localStorage.removeItem('tokenExpireTime');
// 如果当前不在登录页面,则跳转到登录页面
if (window.location.pathname !== '/login') {
window.location.href = '/login';
}
} else {
// 验证Token是否正确
const salt = localStorage.getItem('username')+localStorage.getItem('loginDate')
const token = md5(salt); // 使用md5算法生成Token
if (token === storedToken) {
// Token正确,且在有效期内,继续进行其他操作
// TODO: 继续访问
next()
} else {
// Token错误,跳转到登录页面
localStorage.removeItem('token');
localStorage.removeItem('tokenExpireTime');
// 如果当前不在登录页面,则跳转到登录页面
if (window.location.pathname !== '/login') {
window.location.href = '/login';
}
}
}
}
})
4. 登出代码
src/layout/Layout.vue
这部分还是比较简单的.其实和路由守卫判断token失效是一样的
<script>
//登出
logout() {
//移除用户名
localStorage.removeItem('username');
//移除token
localStorage.removeItem('token');
//跳转至/login页面
this.$router.push('/login');
}
</script>
5. 效果
登录页
清理掉本地存储进行登录
密码验证成功后会生成username,loginDate,token,tokenExpireTime这4个键值对
其中username存放用户名,loginDate存放登录时间(用于产生过期时间和作为md5运算的盐),token存放md5加密后的token,tokenExpireTime存放token过期时间.
此时进行不同页面切换,可以正常访问
如果修改username,loginDate,token则会因为token验证失败跳转到登录页面
再访问其他任意页面就调回了/login页面并清理掉了token和tokenExpireTime
调小tokenExpireTime值一样(将值由1677733016817改为1627733016817)
一样会清理掉token和tokenExpireTime并跳转/login
至此,整个前后端的开发已经完成.下面进入环境部署环节