二、从登陆开始
基本登陆
使用路由导航守卫结合 token 处理视图访问拦截
参考链接:
title: 基于 Token 的验证流程
participant 客户端 as client
participant 服务器 as server
client -> server: 用户名+密码
server --> client: Token 令牌
note over client: 将 Token 存储到本地
在 src/components/login/script.js
中登陆成功,将服务器下发的 token
保存到本地存储:
// 其它代码...
handleLogin () {
axios.post('http://localhost:8888/api/private/v1/login', this.loginForm)
.then(res => {
const {data, meta} = res.data
const {msg, status} = meta
if (status === 200) {
// 将凭证放到到本地存储(会在路由守卫那里使用)
window.localStorage.setItem('token', data.token)
// 跳转到首页
this.$router.push('/')
} else if (status === 400) {
window.alert(msg)
}
})
}
// 其它代码...
在 src/router/index.js
中,添加全局路由导航守卫对非登陆请求进行登陆权限判定:
// 其它代码...
const router = new Router({
// ...
})
router.beforeEach((to, from, next) => {
const {path} = to
if (path !== '/login') { // 如果请求的不是 /login 则校验登陆状态
const token = window.localStorage.getItem('token')
if (!token) { // 如果没有 token 则让其跳转到 /login
next('/login')
} else { // 有 token,让其通过
next()
}
} else {
// 如果用户请求的就是 /login 则直接调用 next() 放行
next()
}
})
export default router
导入 ElementUI
参考链接:
安装依赖:
# 或者 npm install element-ui
yarn add element-ui
在 src/main.js
中加载并配置:
import Vue from 'vue'
import App from './App'
import router from './router'
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'
Vue.use(ElementUI)
Vue.config.productionTip = false
/* eslint-disable no-new */
new Vue({
el: '#app',
router,
components: { App },
template: '<App/>'
})
布局登陆组件
参考链接:
参考 Element 的 Form表单组件文档,我们先来个最简单的登陆表单。
将 src/components/login/template.html
文件内容替换为:
<div>
<el-form :model="loginForm">
<el-form-item>
<el-input v-model="loginForm.username" placeholder="用户名"></el-input>
</el-form-item>
<el-form-item>
<el-input type="password" v-model="loginForm.password" placeholder="密码"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="handleLogin">登陆</el-button>
</el-form-item>
</el-form>
</div>
接下来我们开始调整登陆页面的样式。
首先把公共样式写到 src/assets/css/index.css
文件中。
html, body, #app {
width: 100%;
height: 100%;
}
body {
margin: 0;
padding: 0;
}
然后在 src/main.js
加载:
// 代码略...
// 引入我们的公共样式
import './assets/css/index.css'
// 代码略...
最后,我们分别调整登陆组件的HTML结构、及CSS样式:
src/components/login/template.html
:
<div class="login-wrap">
<div class="login-form">
<el-form :model="loginForm">
<el-form-item>
<el-input v-model="loginForm.username" placeholder="用户名"></el-input>
</el-form-item>
<el-form-item>
<el-input type="password" v-model="loginForm.password" placeholder="密码"></el-input>
</el-form-item>
<el-form-item>
<el-button class="login-submit" type="primary" @click="handleLogin">登陆</el-button>
</el-form-item>
</el-form>
</div>
</div>
src/components/login/style.css
:
.login-wrap {
width: 100%;
height: 100%;
background-color: #2d434c;
display: flex;
justify-content: center;
align-items: center;
}
.login-wrap .login-form {
background-color: #fff;
padding: 50px 50px 20px 50px;
width: 25%;
}
.login-wrap .login-form .login-submit {
width: 100%;
}
为登陆组件加入表单验证
- 为表单中需要验证的表单项
el-form-item
声明prop
属性,属性值给一个有意义的名称
<div class="login-wrap">
<div class="login-form">
<el-form :model="loginForm">
<el-form-item prop="username">
<el-input v-model="loginForm.username" placeholder="用户名"></el-input>
</el-form-item>
<el-form-item prop="password">
<el-input type="password" v-model="loginForm.password" placeholder="密码"></el-input>
</el-form-item>
<el-form-item>
<el-button class="login-submit" type="primary" @click="handleLogin">登陆</el-button>
</el-form-item>
</el-form>
</div>
</div>
- 在组件的
data
中增加一个属性对象loginFormRule
配置prop
字段属性的验证规则
import axios from 'axios'
export default {
// ... 代码略
data () {
return {
loginForm: {
username: '',
password: ''
},
loginFormRule: {
username: [
{ required: true, message: '请输入用户名', trigger: 'blur' }
],
password: [
{ required: true, message: '请输入密码', trigger: 'blur' }
]
}
}
},
// ... 代码略
}
- 在登陆组件的模板中为
el-form
表单组件绑定rules
属性到data
中定义的loginFormRule
<div class="login-wrap">
<div class="login-form">
<el-form :model="loginForm" :rules="loginFormRule">
... 代码略
- 测试验证是否成功
我们在前面做的 1 - 4 步已经完成了基本的表单验证功能。接下来我们要在表单提交登陆发起请求的时候使用 JavaScript 校验是否通过表单验证,表单验证通过再去提交表单。
首先为登陆组件模板的 el-form
组件声明 ref
属性,属性值给一个有意义的名字。
<div class="login-wrap">
<div class="login-form">
<el-form ref="form" :model="loginForm" :rules="loginFormRule">
... 代码略
然后在表单提交的时候调用 JavaScript 判断表单验证是否通过,通过再发起登陆请求。
import axios from 'axios'
export default {
// ... 代码略
methods: {
handleLogin () {
// ['form'] 中的 form 就是 el-form 标签 ref 属性值
this.$refs['form'].validate((valid) => {
if (!valid) {
return
}
axios.post('http://localhost:8888/api/private/v1/login', this.loginForm)
.then(res => {
const {data, meta} = res.data
const {msg, status} = meta
if (status === 200) {
// 将凭证放到到本地存储(会在路由守卫那里使用)
window.localStorage.setItem('token', data.token)
// 跳转到首页
this.$router.push('/')
} else if (status === 400) {
window.alert(msg)
}
})
})
}
}
// ... 代码略
}
使用 Message 消息提示给出操作反馈
无论登陆成功还是登陆失败,我们都应该给出用户一个友好的提示。这里我们可以使用 Element 提供的 Message 消息提示 组件来很方便的实现。
import axios from 'axios'
export default {
// ... 代码略
methods: {
handleLogin () {
// ['form'] 中的 form 就是 el-form 标签 ref 属性值
this.$refs['form'].validate((valid) => {
if (!valid) {
return
}
axios.post('http://localhost:8888/api/private/v1/login', this.loginForm)
.then(res => {
const {data, meta} = res.data
const {msg, status} = meta
if (status === 200) {
// 将凭证放到到本地存储(会在路由守卫那里使用)
window.localStorage.setItem('token', data.token)
// 跳转到首页
this.$router.push('/')
this.$message({
message: '登陆成功',
type: 'success'
})
} else if (status === 400) {
this.$message.error(msg)
}
})
})
}
}
// ... 代码略
}