• vue beforeEach 路由拦截 cookie 登录管理 jsonwebtoken 表单提交校验 sessionStorage localStorage


    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,
    }设置
    
    • 1
    • 2
    • 3
    • 4

    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,并跳转’/’

    //server\security\token.ts
    import jwt from 'jsonwebtoken';
    import { sign,  verify } from 'jsonwebtoken';
    const secretKey = 'secretkey'   //secret
    const expiresIn = 60;    //时效 (秒)
    
    //生成jwt
    export const generateToken=(user:string) =>{ 
        const token = jwt.sign({user}, secretKey, {
            expiresIn: expiresIn,
           });
        return token
    }
     
    //解析jwt
    export const verifyToken=(token:any)=> {
        return jwt.verify(token, secretKey)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    //server\index.ts 
    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})
        }
    
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    //src\router\index.ts
    import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router'
    
    //verifyToken(token)在这用不了,在express服务器里可以使用
    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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    //src\utils\cookie.ts
    /**
     * @description 保存cookie
     * @param {Object} json 需要存储cookie的对象
     * @param {Number} days 默认存储多少天
     */
    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;
        }
    }
    
    /** 
     * @description 获取cookie
     * @param {String} name 需要获取cookie的key
     */
    function get(name: string) {
        // console.log(document.cookie, '------')
        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
    }
    
    /** 
     * @description 删除cookie
     * @param {String} name 需要删除cookie的key
     */
    function clear(name: string) {
        console.log('clear cookie ',name)
        const json:any = {};
        json[name]=''
        set(json, 0)
    }
    
    export default {
        set,
        get,
        clear
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    //src\views\login\login.vue
    <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>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    //src\components\content.vue
    <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>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
  • 相关阅读:
    章节六:带参数请求数据
    黑客(网络安全)技术自学30天
    Java基础知识-语法
    对象的解构赋值(基本用法1)
    SpringBoot集成Kafka
    国家电网王继业:企业数字化发展的“3-3-4”框架
    朋友圈一键转发(可修改文案),无需多个账号复制粘贴
    蓝桥杯的一些技巧
    对接淘宝天猫平台的第一篇
    实力认证|万应工场荣膺2022中国低代码平台行业应用卓越奖!
  • 原文地址:https://blog.csdn.net/weixin_43292547/article/details/126333249