Vue项目中用户登录及token验证及流程图
在前后端完全分离的情况下,Vue项目中实现token验证大致思路如下:
简单举例说明:
① 调登录接口成功,在回调函数中将token存储到localStorage和vuex中(login.vue中)
② store文件夹下的index.js
③ 路由守卫(router文件夹下的index.js)
④ 请求头加token
⑤ 如果前端拿到状态码为401,就清除token信息并跳转到登录页面
流程图:
VUE项目 注册与登录效果实现
template
div class="login-section"
el-form
label-position="top" label-width="100px" class="demo-ruleForm"
:rules="rules"
:model="rulesForm"
status-icon
ref="ruleForm"
el-form-item label="用户名" prop="name"
el-input type="text" v-model="rulesForm.name"/el-input
/el-form-item
el-form-item label="密码" prop="password"
el-input type="password" v-model="rulesForm.password"/el-input
/el-form-item
el-form-item
el-button type="primary" @click="submitForm('ruleForm')" 提交/el-button
el-button 重置/el-button
/el-form-item
/el-form
/div
/template
script
import {register} from '@/service/api';
export default {
data() {
return {
rulesForm:{
name:'',
password:''
},
rules:{
name:[
{required:true,message:'请输入名字',trigger:"blur"},
{min:1,max:5,message:"长度3-5",trigger:"blur"}
],
password:[
{required:true,message:'请输入密码',trigger:"blur"},
{min:3,max:5,message:"长度3-5",trigger:"blur"}
]
}
};
},
methods: {
submitForm(formName){
this.$refs[formName].validate((valid)={
if(valid){
//如果校检通过,在这里向后端发送用户名和密码
register({
name: this.rulesForm.name,
password: this.rulesForm.password,
}).then((data)={
console.log(data)
if(data.code === 0){
localStorage.setItem('token',data.data.token);
window.location.href= '/';
}
if(data.code === 1){
this.$message.error(data.mes)
}
});
}else{
console.log("error submit!!");
return false;
}
});
}
}
}
/script
style lang="stylus"
.login-section
padding 0px 20px
/style
template
div class="login-section"
el-form
label-position="top"
label-width="100px" class="demo-ruleForm"
:rules="rules"
:model="rulesForm"
status-icon
ref="ruleForm"
el-form-item label="用户名" prop="name"
el-input type="text" v-model="rulesForm.name"/el-input
/el-form-item
el-form-item label="密码" prop="password"
el-input type="password" v-model="rulesForm.password"/el-input
/el-form-item
el-form-item
el-button type="primary" @click="submitForm('ruleForm')"提交/el-button
el-button重置/el-button
/el-form-item
/el-form
/div
/template
script
import {login} from '@/service/api';
export default {
data() {
return {
//存储数据的对象
rulesForm:{
name:'',
password:''
},
rules:{
name:[
{required:true,message:'请输入名字',trigger:"blur"},
{min:1,max:5,message:"长度3-5",trigger:"blur"}
],
password:[
{required:true,message:'请输入密码',trigger:"blur"},
{min:3,max:5,message:"长度3-5",trigger:"blur"}
]
}
};
},
methods: {
submitForm(formName){
this.$refs[formName].validate((valid)={
if(valid){
//如果校检通过,在这里向后端发送用户名和密码
login({
name: this.rulesForm.name,
password: this.rulesForm.password,
}).then((data)={
console.log(data)
if(data.code === 0){
localStorage.setItem('token',data.data.token);
window.location.href= '/';
}
if(data.code === 1){
this.$message.error(data.mes)
}
});
}else{
console.log("error submit!!");
return false;
}
});
}
}
}
/script
style lang="stylus"
.login-section
padding 0px 20px
/style
import Vue from 'vue'
import Router from 'vue-router'
Vue.use(Router)
import Store from '@/store'
import {userInfo} from '@/service/api.js'
import Login from '@/views/user-login/index.vue'
const router = new Router({
mode:"history",
routes:[
{
path:'/login',
name:"login",
title:"登录页",
component:Login,
meta:{
login:true
}
}
]
});
//路由守卫
router.beforeEach( async (to,from,next) = {
/*
有些路由是需要登录的,判断登录状态
1.没有登录:跳转到登录页
2.登录:直接进入
有些路由是不需要登录的,直接进入
ps:是否需要登录 --meta
*/
const token = localStorage.getItem('token');
const isLogin = !!token;
//进入路由的时候,需要向后端发送token,验证是否合法
const data = await userInfo();
Store.commit('chageUserInfo',data.data)
if(to.matched.some(item = item.meta.login)){//需要登录
console.log("需要登录");
if(isLogin){//已经登录的,直接通过
if(data.error === 400){//后端告诉你,登录不成功
next({name:'login'});
localStorage.removeItem('token');
return;
}
if(to.name === 'login'){
next({name:'home'});
}else{
next();
}
return;
}
if(!isLogin to.name === 'login'){//未登录,但是要去登录页
next();
}
if(!isLogin to.name !== 'login'){//未登录,去的也不是登录页
next({name:'login'});
}
}else{
next();
}
})
export default router;
11 | 登录前端实现
前端任务点,编写登录请求函数,和 用户注册 类似,前端拿到用户名和密码发起 POST 请求。
收到 token 如何持久化存储,如何让每次请求都携带 token 是这里的点。
用户登录的接口详情可以点 这里 。
这里有可以优化的点,未来可能需要添加验证码等附加信息,这个时候就需要添加函数参数,就会比较麻烦,可以将参数数据格式包装成一个对象。当然,这里还是使用第一种方法了。
这不是重点,重点是登录成功后,我们要做的事情。
按照接口约定,登录成功我们可以得到如下信息:
这里我们要用到 token 字段,是我们现在有 token 了,但一刷新就没了,所以我们要做一下持久化存储,你想存哪里就存哪里,只要你能找到。这里就存储 localStorage 中了,在 Chorme86 中你甚至可以存到一个本地的文本文件中,只不过读取速度比较慢罢了。
除了 token,我们还要将用户信息存下来,比如首页展示用的用户头像等信息。
关于本地信息的安全性问题,本地保存的用户信息并不作为数据请求的凭证,仅供展示使用,当用户更改本地的用户信息对于登录的状态不会有影响,因为后端的判断依据是 token,token 有效就登录成功,而不是说本地存储的用户信息是谁服务端就认为你是谁,前端是不可信的。这种登录方式的危险点在于用户 token 被盗,但这很难避免,最不安全的是人。。。
登录成功,返回首页,用户名或者是用户头像并没有同步更新,这是因为,这里是单页应用,你在 login 页面将登录用户信息存到 localStorage 中,然后跳转到了首页,此时页面没有刷新,而 localStorage 中的信息没有及时更新到 DOM 中,此时的用户信息还是你没有进入 login 页面的用户信息,自然是无法展示的,怎么解决呢?很简单,刷新一下。
当页面刷新时,用户信息会从 localStorage 中读取,显示的就是现在的登录用户了,但。。。
我不想刷新。
也很简单,搞成响应式数据就好了呀。来人呀,上Vuex。
当你将 token 存在 cookie 中,前端并不需要主动设置,默认就携带传给了服务端,而这里我们存到 Authorization 中,就需要我们设置一下,拦截请求,在请求发送前添加 token。
好的,来捋一捋流程。
用户访问 /login,被前端路由处理,指向Login.vue,用户看到登录框,填入自己的账号,当用户填写账号时,name password被实时监听,同时会对登录按钮的可操作产生影响,只有当用户将账密输入完整时,登录按钮可用。
前端收集用户信息,调用 network 中封装的 longin 请求函数,该请求发送前被拦截,添加 token,可能为空,使用账密登录时,token没实际效用。
后端检查成功给响应,前端将响应中数据的 token 通过触发 mutations 更新 Vuex 中 state,同时,将该 token 存到 localStorage,以免用户关掉页面导致 token 丢失。
登录成功跳到应用首页,用户头像等信息通过 Vuex 获取,因为 Vuex 中的数据是响应式的,此时从 login 跳转到首页,用户头像等信息也会得到相应的更新。
当用户新增文章时,只需向服务器传文章数据就可以了,而对于文章作者的相关信息则由后端从请求头中的 token 解析得到,这里需要注意,前端不要将本地的用户信息作为准确的作者信息,对于用户可以伪造的信息要做最小化的信任,用户完全有能力将本地用户名从张三改为李四,而最终作者是那个则需要由用户提供的 token 来判定,虽说 token 也有可能被伪造,但难度相对较大,往往是被窃取的可能性更大。
无密码登录其实还是需要“密码”的,只不过是换了一个临时性的对人不可读的字符串来代替罢了,并且每次请求帮你填好了。
在不考虑安全性的情况下本质上其实就是你将密码存到了浏览器里,然后你每次访问网站时让浏览器帮你输入用户名和密码,这个过程你是无感知的,这样自己就不用像个憨憨一样每次刷新就要填一遍表单。
填表是一件非常无聊的事。
要学一波 TypeScript 了呀。
Vue项目:后台管理系统登录页的记住密码的功能如何实现?
当在做后台管理系统时,经常需要做到点击记住密码,然后登录进入系统后,一番操作后退出系统希望能够自动的记住上次登录的账号密码,这个功能实现并不算复杂。
记住密码的选项的值动态的绑定一个checked值,这个值默认为false,当选中的时候才去赋予一个true值,然后通过这个值当登录将账号密码提交的时候,根据checked的布尔值将账号密码存到本地存储中,如果为true则存账号密码,如果为false,则存个空对象进去。当用户操作完退出登录时,会退到登录页,此时会执行一次login组件的生命周期,就可以在生命周期中将本地存的值再次重新赋予到登录页的表单中去,这样就实现了登录时记住密码的功能。
3.1.1、登录的表单
3.1.2、从父组件接收过来的数据
loginForm:表单的账号密码的数据,hasChecked:是否选择记住密码
3.1.3、登录表单的校验
3.1.4、深度监听登录表单form
主要是监听退回登录页时,看表单页的数据是否填充,如果有数据填充,触发监听,并且执行init()初始化表单的方法。
3.1.5、init初始化
将选项布尔值重新赋值
3.2.1、子组件的引入
3.2.2、判断本地缓存中是否有数据,有的话那么就在生命周期中去给表单项进行赋值操作
3.2.4、提交按钮进行的逻辑操作
这部分需要判断是否选择了记住密码,如果勾选了,那么就将当前的账号密码存入,如果没有,那么就存入个空对象,一方面清空之前存入的账号密码,另一方面保证了下次登录不会带入数据。
3.2.5、保存用户设置的方法
这个方法是去保存用户是否勾选了记住密码的
最后大致的功能就实现了,当然为了安全性,最好在存入本地之前进行md5加密(其他的加密也行,比如:AES加密),然后在生命周期去赋值的时候再去进行解密赋值到表单项上去,这样安全性就提升了。
vue项目实现用户登录 以及携带token
article class="_2rhmJa"
调取登录接口 (首先明确一下要做到事情)
在前后端完全分离的情况下,Vue项目中实现token验证大致思路如下:
1、第一次登录的时候,前端调后端的登陆接口,发送用户名和密码
2、后端收到请求,验证用户名和密码,验证成功,就给前端返回一个token
3、前端拿到token,将token存储到localStorage和vuex中,并跳转路由页面
4、前端每次跳转路由,就判断 localStroage 中有无 token ,没有就跳转到登录页面,有则跳转到对应路由页面
5、每次调后端接口,都要在请求头中加token
6、后端判断请求头中有无token,有token,就拿到token并验证token,验证成功就返回数据,验证失败(例如:token过期)就返回401,请求头中没有token也返回401
7、如果前端拿到状态码为401,就清除token信息并跳转到登录页面
调取登录接口成功,会在回调函数中将token存储到localStorage和vuex中
1.template
div
/div
/template
export default {
data () {
},
methods: {
/////判读账号密码是否输入,没有则alert 出来
}
};
在store文件夹下的index.js 添加 token
import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);
const store = new Vuex.Store({
state: {
},
mutations: {
}
});
export default store;
二,配置 路由导航守卫
router文件夹下的index.js
import Vue from 'vue';
import Router from 'vue-router';
import login from '@/components/login';
import home from '@/components/home';
Vue.use(Router);
const router = new Router({
routes: [
]
});
// 导航守卫
// 使用 router.beforeEach 注册一个全局前置守卫,判断用户是否登陆
router.beforeEach((to, from, next) = {
if (to.path === '/login') {
} else {
}
});
export default router;
三、请求头加token 在 main.js中添加
// 添加请求拦截器,在请求头中加token
axios.interceptors.request.use(
config = {
},
error = {
});
token的过期可以自定义
四、如果前端拿到状态码为401,就清除token信息并跳转到登录页面
localStorage.removeItem('Authorization');
this.$router.push('/login');
/article
66人点赞
前段学习