server\security\token.ts 使用jsonwebtoken生成token,本demo没有使用token的过期时间属性
server\index.ts 其他express服务器提供的api,验证用户登录信息。 如果用户登录成功,往用户cookie里有token信息(包含user信息)。cookie有效期10秒
src\router\index.ts 用router.beforeEach对所有url进行拦截,如果to.matched数组里有meta.needlogin:true属性的对象,说明需要登录后才能访问。对于此类路径,如果cookie的token里没有user信息(说明用户没有登录),则通过next(‘/login’)跳转登录页面。其他情况下next()直接放行。 localStorage:浏览器多个页面共享数据 sessionStorage :单个页面的数据 localStorage和sessionStorage 在vue文件可以直接使用,在ts文件不能直接使用
meta.needlogin:true属性在routes的对应url下用
meta: {
needlogin: true,
}设置
src\utils\cookie.ts 网上随便找的cookie的工具类,包含cookie的添加,清楚,查询方法。 不知道什么原因,vue-cookie和js-cookie在非服务器的ts文件里都用不了。
src\views\login\login.vue 登录页面。 rules里 { required: true, message: “请输入”, trigger: “blur” }设置了blur时进行校验(提交时不校验),按下按钮提交时this.$refs.loginFormC.validate(valid) 再次对表单进行校验。
src\components\content.vue 提供logout功能,清除cookie里的token,并跳转’/’
import jwt from 'jsonwebtoken';
import { sign, verify } from 'jsonwebtoken';
const secretKey = 'secretkey'
const expiresIn = 60;
export const generateToken=(user:string) =>{
const token = jwt.sign({user}, secretKey, {
expiresIn: expiresIn,
});
return token
}
export const verifyToken=(token:any)=> {
return jwt.verify(token, secretKey)
}
const express = require('express');
const bodyParser=require('body-parser')
const app=express();
app.use(bodyParser.urlencoded({extended:false}))
app.use(bodyParser.json())
import sqlfun from './pgsql';
import {generateToken,verifyToken} from './security/token';
const cookieParser = require('cookie-parser');
app.use(cookieParser());
const port = 8081;
app.listen(port, () => console.log(`API服务器监听${port}端口!`));
app.post('/api/login', (req: any, res: any) => {
if(req.body.user=='aa'&&req.body.pass=='aa'){
const token=generateToken(req.body.user)
res.cookie("token", token, { maxAge: 1000*10});
res.send({status: 200,token:token})
}else{
res.send({status: 500})
}
})
import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router'
import { verifyToken } from "../../server/security/token";
import jwt_decode from "jwt-decode";
import cookie from '../utils/cookie'
const routes: Array<RouteRecordRaw> = [
{
path: '/demo',
meta: {
needlogin: true,
},
component: layoutC,
children: [
{
path: '',
name: 'home',
component: homeC,
},
]
},
{
path: '/login',
name: 'login',
component: loginC,
meta: {
needlogin: false,
},
},
]
const router = createRouter({
history: createWebHistory(process.env.BASE_URL),
routes
})
router.beforeEach((to, from, next) => {
const count=sessionStorage.getItem('count')||'0'
sessionStorage.setItem('count',1+parseInt(count)+'')
const count2=localStorage.getItem('count')||'0'
localStorage.setItem('count',2+parseInt(count2)+'')
console.log('to', to.matched)
console.log('sessionStorage',sessionStorage.getItem('count'))
console.log('localStorage',localStorage.getItem('count'))
if (to.matched.length == 0) {
console.log(1)
next()
return
}
if (to.matched.some(ele => ele.meta.needlogin)) {
const token: string = cookie.get("token") || '';
const tokenobj: any =token?jwt_decode(token): {}
console.log('>>',token, tokenobj)
if (tokenobj['user']) {
console.log(2)
next()
} else {
console.log(3)
next('/login')
}
} else {
console.log(4)
cookie.set({'a':'1','b':'3'},1)
cookie.clear('aaa')
next()
}
})
export default router
function set(json: { [x: string]: string; }, days: number) {
const date = new Date(
new Date().getTime() + days * 24 * 60 * 60 * 1000
).toUTCString();
for (const key in json) {
document.cookie = key + "=" + json[key] + "; expires=" + date;
}
}
function get(name: string) {
const arr = document.cookie.split(';')
for (const s in arr) {
if (arr[s].split('=')[0].trim() == name)
return arr[s].split('=')[1].trim()
}
return null
}
function clear(name: string) {
console.log('clear cookie ',name)
const json:any = {};
json[name]=''
set(json, 0)
}
export default {
set,
get,
clear
}
<template style="text-align: center;">
<div>
<h1>login</h1>
<el-form
ref="loginFormC"
:model="loginForm"
:rules="rules"
label-width="100px"
>
<el-form-item label="用户名" prop="user">
<el-input v-model="loginForm.user"></el-input>
</el-form-item>
<el-form-item label="密码" prop="pass">
<el-input v-model="loginForm.pass"></el-input>
</el-form-item>
</el-form>
<el-button type="success" @click="login">登 录 </el-button>
</div>
</template>
<script>
import api from "../../api/index";
export default {
data() {
return {
loginForm: {
user: "",
pass: "",
},
rules: {
user: [
{ required: true, message: "请输入", trigger: "blur" },
{ min: 2, max: 9, message: "长度2到9", trigger: "blur" },
],
pass: [{ required: true, message: "请输入", trigger: "blur" }],
},
};
},
methods: {
login() {
this.$refs.loginFormC.validate((valid) => {
if (valid) {
api.login({ user: this.loginForm.user, pass: this.loginForm.pass })
.then((res) => {
if (res.data.status == 200) {
this.$message({ message: "登录成功" });
this.$router.push("/demo");
} else {
this.$message({ message: "登录失败", type: "error" });
}
});
}
})
},
},
};
</script>
<style>
</style>
<template>
<div>
<i class="el-icon-setting" @click="logout()"></i>
</div>
</div>
</template>
<script>
import cookie from "../utils/cookie";
export default {
methods: {
logout() {
cookie.clear('token');
this.$router.push('/');
},
},
};
</script>
<style lang="less" scoped>
</style>
|