1、封装登录接口 api,新建 src/api/auth.js
,添加如下代码:
import request from "@/utils/request";
// 登录接口
export function fetchLogin(data) {
return request({
url: "/auth/sign_in",
method: "post",
data,
});
}
2、准备登录路由,在 router/index.js
中添加登录的路由
.
import LoginView from "../views/LoginView.vue";
.
{
path: "/login",
name: "Login",
component: LoginView,
},
.
.
3、新建 src/views/LoginView.vue
组件并请求登录接口,添加代码:
<template>
<div class="wrapper">
<div class="wrap">
<div class="layout_panel">
<div class="layout" id="layout">
<div id="main-content">
<div class="mainbox form-panel" id="login-main">
<div class="lgnheader">
<div class="header_tit t_c">
<em id="custom_display_1" class="milogo"></em>
<h4 class="header_tit_txt" id="login-title">
长乐未央帐号登录
</h4>
</div>
</div>
<div class="tabs-con tabs_con now" data-con="pwd">
<div>
<div class="login_area" id="login-main-form">
<div class="loginbox c_b">
<div
class="lgn_inputbg c_b login-panel pwdLogin sms_login"
>
<label
id="region-code"
class="labelbox login_user c_b disable add_regioncode"
>
<input
class="item_account"
autocomplete="off"
type="text"
v-model="user.username"
id="username"
placeholder="用户名"
/>
</label>
<label class="labelbox pwd_panel c_b">
<input
class="item_account"
type="password"
placeholder="密码"
autocomplete="off"
id="pwd"
v-model="user.password"
/>
</label>
</div>
<div class="btns_bg">
<input
class="btnadpt"
id="login-button"
type="button"
value="立即登录"
@click="handleSubmit"
/>
</div>
<div class="other_panel clearfix">
<div class="reverse" id="extra-links">
<div
class="n_links_area reg_forget_links reg-forget-links"
id="custom_display_64"
>
<a class="outer-link" href=""
>还没有账号,现在注册</a
>
</div>
</div>
<div
class="other_login_type sns-login-container"
id="custom_display_16"
></div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import { fetchLogin } from "@/api/auth";
export default {
data() {
return {
user: {
username: "",
password: "",
},
};
},
methods: {
async handleSubmit() {
let res;
try {
res = await fetchLogin(this.user);
localStorage.token = res.data.token;
this.$router.push({ name: "home" });
} catch (err) {
this.$toast.center(err.message);
}
},
},
};
</script>
4、封装 axios
拦截器,验证 token
在 utils/request.js
中,全部代码:
import axios from "axios";
const service = axios.create({
baseURL: process.env.VUE_APP_BASE_API,
timeout: 5000,
});
// request拦截器
service.interceptors.request.use(
(config) => {
// do something 在发送请求前
const token = localStorage.token;
if (token) {
// 让每个请求携带token
// ['X-Token']为自定义key
// 请根据实际情况自行修改
config.headers["token"] = token;
}
return config;
},
(error) => {
// do something 当请求错误
console.log(error); // for debug
return Promise.reject(error);
}
);
// response拦截器
service.interceptors.response.use(
/**
* 如果你想获取 http 信息,例如 headers 或 status
* 请 return response => response
*/
/**
* 下面的注释为通过response自定义code来标示请求状态,当code返回如下情况为权限有问题,登出并返回到登录页
* 如通过xmlhttprequest 状态码标识 逻辑可写在下面error中
*/
(response) => {
const res = response.data;
// console.log(111, res);
// 如果返回的自定义code不是20000, 认定为error。
if (res.code !== 20000) {
// 单独判断除 20000 以外的响应码,返回 Promise 对象,不然页面会跳过这些响应码执行刷新
if (res.code === 50001 || res.code === 50008 || res.code === 50014) {
return Promise.reject(new Error(res.message || "Error"));
}
// 清除token
localStorage.removeItem("token");
// 跳转到登录页
location.href = "/login";
return Promise.reject(new Error(res.message || "Error"));
} else {
return res;
}
},
(error) => {
console.log("err" + error); // for debug
return Promise.reject(error);
}
);
export default service;
5、在 router/index.js
中,通过路由全局前置守卫和路由元信息设置访问权限。
.
.
{
path: "/carts",
name: "carts",
component: () => import("../views/CartsView.vue"),
meta: { requiresAuth: true },
},
.
.
// 路由导航守卫
router.beforeEach((to, from, next) => {
if (to.matched.some((record) => record.meta.requiresAuth)) {
const token = localStorage.token;
if (token) {
next(); // 执行下一步操作
} else {
next({
path: "/login", // 跳转到登录页面
});
}
} else {
next(); // 确保一定要调用 next()
}
});
.
.
例如这里通过 meta 给购物车设置元信息,代表购物车需要用户认证后才能访问。