🍊 编程有易不绕弯,成长之路不孤单!
目录
[🍊 编程有易不绕弯,成长之路不孤单!](#🍊 编程有易不绕弯,成长之路不孤单!)
[2.1 the-header组件](#2.1 the-header组件)
[2.2 store工具](#2.2 store工具)
[2.3 router路由配置修改](#2.3 router路由配置修改)
一、今日目标
上篇文章链接:【wiki知识库】07.用户管理前端模块的添加-前端部分-CSDN博客
之前的一篇文章带大家实现了用户管理的功能,网站内我们并未提供注册功能,而是在一开始就初始化了一个管理员账号,只有登录管理员的账号后才能对用户进行增删改查功能。这次我们要开发网站的登录功能。
下方的图片能够看到,这是没有登录的情况,导航栏中的菜单并没有展示一些操作功能。
当我们登录账号后就会展示对应的功能。
这个事情不难,说的简单一些呢就是前端会从你的本地浏览器的存储空间中找出有没有一个可以证明你登陆过的token,如果有这个token就会展示对应的功能选项,否则的话就不会展示。这个token就是在我们登录之后返回给前端的,并且由前端来将其保存到本地浏览器的一个存储空间当中。
二、前端Vue模块的修改
在之前我们修改过the-header组件,今天我们还要修改,为其添加上用户登录的一些代码。
2.1 the-header组件
这个代码我自己弄了半天,因为这个布局总是展示错误,就是<a-menu>标签后边
不能去加登录按钮,需要在之前加。
html<template> <a-layout-header class="header"> <div class="logo">熊哈哈</div> <div> <a-popconfirm title="确认退出登录?" ok-text="是" cancel-text="否" @confirm="logout()" > <a class="login-menu" v-show="user.id"> <span>退出登录</span> </a> </a-popconfirm> <a class="login-menu" v-show="user.id"> <span>您好:{{user.name}}</span> </a> <a class="login-menu" v-show="!user.id" @click="showLoginModal"> <span>登录</span> </a> </div> <a-menu theme="dark" mode="horizontal" :style="{ lineHeight: '64px' }" > <a-menu-item key="/"> <router-link to="/">首页</router-link> </a-menu-item> <a-menu-item key="/about"> <router-link to="/about">关于我们</router-link> </a-menu-item> <a-menu-item key="/admin/user" :style="user.id? {} : {display:'none'}"> <router-link to="/admin/user">用户管理</router-link> </a-menu-item> <a-menu-item key="/admin/ebook" :style="user.id? {} : {display:'none'}"> <router-link to="/admin/ebook">电子书管理</router-link> </a-menu-item> <a-menu-item key="/admin/category" :style="user.id? {} : {display:'none'}"> <router-link to="/admin/category">分类管理</router-link> </a-menu-item> </a-menu> <a-modal title="登录" v-model:visible="loginModalVisible" :confirm-loading="loginModalLoading" @ok="login" > <a-form :model="loginUser" :label-col="{ span: 6 }" :wrapper-col="{ span: 18 }"> <a-form-item label="登录名"> <a-input v-model:value="loginUser.loginName" /> </a-form-item> <a-form-item label="密码"> <a-input v-model:value="loginUser.password" type="password" /> </a-form-item> </a-form> </a-modal> </a-layout-header> </template>
然后就是script部分的代码。
html<script lang="ts"> import { defineComponent, ref, computed } from 'vue'; import axios from 'axios'; import { message } from 'ant-design-vue'; import store from "@/store"; export default defineComponent({ name: 'the-header', setup () { // 登录后保存 const user = computed(() => store.state.user); // 用来登录 const loginUser = ref({ loginName: "", password: "" }); const loginModalVisible = ref(false); const loginModalLoading = ref(false); const showLoginModal = () => { loginModalVisible.value = true; }; // 登录 const login = () => { console.log("开始登录"); loginModalLoading.value = true; axios.post('/user/login', loginUser.value).then((response) => { loginModalLoading.value = false; const data = response.data; if (data.success) { loginModalVisible.value = false; message.success("登录成功!"); store.commit("setUser", data.content); } else { message.error(data.message); } }); }; // 退出登录 const logout = () => { console.log("退出登录开始"); axios.get('/user/logout/' + user.value.token).then((response) => { const data = response.data; if (data.success) { message.success("退出登录成功!"); store.commit("setUser", {}); } else { message.error(data.message); } }); }; return { loginModalVisible, loginModalLoading, showLoginModal, loginUser, login, user, logout } } }); </script>
最后是style部分的代码。
html<style scoped> .logo { width: 120px; height: 31px; float: left; color: white; font-size: 18px; } .login-menu { float: right; color: white; padding-left: 10px; } </style>
2.2 store工具
在上方的代码中你会看到这句话。
htmlimport store from "@/store";
store是vue中的状态管理模式,用来存储和管理vue中的状态信息。说白了就是可以存储一些你需要的全局性质的信息。具体的内容还要大家自己去了解。我忘记了这段代码之前有没有提供了,所以我索性在提供一次。
看一下下方的代码,用到了一个变量SessionStorage,这个变量用来将你登陆后的token保存在浏览器中。其中的state保存了user数据,这个数据就是从SessionStorage中获取的,或者是在你登陆后自动设置的。
javascriptimport {createStore} from 'vuex' declare let SessionStorage: any; const USER = "USER"; const store = createStore({ state: { user: SessionStorage.get(USER) || {} }, mutations: { setUser(state, user) { console.log("store user:", user); state.user = user; SessionStorage.set(USER, user); } }, actions: {}, modules: {} }); export default store;
再看看下方的代码。菜单标签的属性上加上了判断条件,判断的就是当前的SessionStorage中是否有user被存储,如果没有那么就不会展示菜单。
html<a-menu theme="dark" mode="horizontal" :style="{ lineHeight: '64px' }" > <a-menu-item key="/"> <router-link to="/">首页</router-link> </a-menu-item> <a-menu-item key="/about"> <router-link to="/about">关于我们</router-link> </a-menu-item> <a-menu-item key="/admin/user" :style="user.id? {} : {display:'none'}"> <router-link to="/admin/user">用户管理</router-link> </a-menu-item> <a-menu-item key="/admin/ebook" :style="user.id? {} : {display:'none'}"> <router-link to="/admin/ebook">电子书管理</router-link> </a-menu-item> <a-menu-item key="/admin/category" :style="user.id? {} : {display:'none'}"> <router-link to="/admin/category">分类管理</router-link> </a-menu-item> </a-menu>
2.3 router路由配置修改
有了上方的代码我们就能够在用户不登陆的状态下隐藏这些功能菜单,但是这样只能隐藏菜单,而不是彻底的屏蔽掉没有登陆的用户去访问这些组件。用户还是可以通过路由的路径访问到对应的组件。所以我们还要在路由配置中配置一些信息来防止这样的行为。
bash{ path: '/admin/user', name: 'AdminUser', component: AdminUser, meta: { loginRequire: true }
以用户管理为例,我们要在这个用户管理的组件上加上一些信息。加上下边这个配置项后,就意味着这个组件是需要登陆后访问的。这样我们就可以进行后续操作,来组织用户在不登陆的状态下访问组件。注意:所有需要登陆才能访问的组件都要加上这个配置信息。
接下来要配置的是路由拦截,顾名思义,在我们访问路由的时候进行拦截,在拦截方法中判断组件是否需要登陆访问,并且判断用户是否登录。如果组件需要登陆访问并且用户没有登陆的话就会跳到主页去。这样就防止了用户在不登陆的情况下通过路径访问路由了。
javascriptrouter.beforeEach((to, from, next) => { // 要不要对meta.loginRequire属性做监控拦截 if (to.matched.some(function (item) { console.log(item, "是否需要登录校验:", item.meta.loginRequire); return item.meta.loginRequire })) { const loginUser = store.state.user; if (Tool.isEmpty(loginUser)) { console.log("用户未登录!"); next('/'); } else { next(); } } else { next(); } });
2.4 添加axios拦截
在我们每次向后端发送请求的时候,需要携带上当前登录用户的token,用于用户身份的校验,这里先不多说。
这个拦截器会让你的axios请求每一次请求后端之前先做一些事情,这里仅仅是携带上了用户的token,其实还可以做很多的事情。
javascript/** * axios拦截器 */ axios.interceptors.request.use(function (config) { console.log('请求参数:', config); const token = store.state.user.token; if (Tool.isNotEmpty(token)) { config.headers.token = token; console.log("请求headers增加token:", token); } return config; }, error => { return Promise.reject(error); }); axios.interceptors.response.use(function (response) { console.log('返回结果:', response); return response; }, error => { console.log('返回错误:', error); const response = error.response; const status = response.status; if (status === 401) { // 判断状态码是401 跳转到首页或登录页 console.log("未登录,跳到首页"); store.commit("setUser", {}); message.error("未登录或登录超时"); router.push('/'); } return Promise.reject(error); });