Login.vue
// Login.vue
<div>
<div class="logo">
<img src="https://img.kaikeba.com/logo-new.png" alt="">
</div>
<!-- <cube-button>登录</cube-button> -->
<cube-form
:model="model"
:schema="schema"
@submit.prevent="handleLogin"
@validate="haneldValidate"
>
</cube-form>
</div>
分别设置model和schema
model: { username: "", passwd: "" },
schema: {
fields: [
{
type: "input",
modelKey: "username",
label: "用户名",
props: {
placeholder: "请输入用户名"
},
rules: {
// 校验规则
required: true
},
trigger: "blur"
},
]
}
发起登录请求,Login.vue
this.$store
.dispatch("login", this.model)
.then(success => {})
.catch(error => {});
登录动作,store.js
import us from "./service/user";
login({ commit }, model) {
return us.login(model).then(res => {
const {token} = res.data;
if (token) {
localStorage.setItem("token", token);
commit("setLoginState", true);
return true;
}
return false;
});
}
接口服务,service/user.js
import axios from "axios";
export default {
login(user) {
return axios.get("/api/login", {params: user});
}
};
vue.config.js中,模拟接口
configureWebpack:{
devServer:{
before(app){
app.get("/api/login", function(req, res) {
const { username, passwd } = req.query;
console.log(username, passwd);
if (username == "kaikeba" && passwd == "123") {
res.json({ code: 1, token: "jilei" });
} else {
res
.status(401)
.json({ code: 0, message: "用户名或者密码错误" });
}
});
}
}
}
http拦截器
有了token之后,每次http请求发出,都要加载header上
// interceptor.js
const axios = require("axios");
export default function() {
axios.interceptors.request.use(config => {
const token = localStorage.getItem('token')
if (token) {
config.headers.token = token;
}
return config;
});
}
// 启用,main.js
import interceptor from './interceptor'
interceptor();
接口验证
// mock接口,vue.config.js
function auth(req, res, next) {
if (req.headers.token) {
// 已认证
next()
} else {
res.sendStatus(401)
}
}
app.get("/api/userinfo", auth, function(req, res) {
res.json({ code: 1, data: { name: "tom", age: 20 } });
});
http拦截响应
// interceptor.js
export default function(vm) { // 传入vue实例
// ...
// 响应拦截
axios.interceptors.response.use(null, err => {
if (err.response.status === 401) {
// 清空vuex和localstorage
vm.$store.dispatch("logout");
// 跳转login
vm.$router.push("/login");
}
return Promise.reject(err);
});
}
令牌机制\
服务端,~/server/server.js
const Koa = require("koa");
const Router = require("koa-router");
const jwt = require("jsonwebtoken");
const jwtAuth = require("koa-jwt");
const secret = "it's a secret";
const app = new Koa();
const router = new Router();
router.get("/api/login", async ctx => {
const { username, passwd } = ctx.query;
console.log(username, passwd);
if (username == "kaikeba" && passwd == "123") {
// 生成令牌
const token = jwt.sign(
{
data: { name: "kaikeba" }, // 用户信息数据
exp: Math.floor(Date.now() / 1000) + 60 * 60 // 过期时},
secret
);
ctx.body = { code: 1, token };
} else {
ctx.status = 401;
ctx.body = { code: 0, message: "用户名或者密码错误" };
}
});
router.get(
"/api/userinfo",
jwtAuth({ secret }),
async ctx => {
ctx.body = { code: 1, data: { name: "jerry", age: 20 } };
}
);
app.use(router.routes());
app.listen(3000);
服务器代理,vue.config.js
devServer: {
//代理配置
proxy: {
"/api": {
target: "http://127.0.0.1:3000/",
changOrigin: true
}
},
// before(app) { ... }
}
拦截器处的修改,interceptor.js
config.headers.Authorization = 'Bearer ' + token;
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。