Vue.js 实现后台用户登录

1、封装登录接口 api,新建 src/api/auth.js ,添加如下代码:

import request from "@/utils/request";

// 登录
export function userLogin(data) {
  return request({
    url: "/admin/auth/sign_in",
    method: "post",
    data,
  });
}

2、准备登录路由,在 router/index.js 中添加登录的路由

.
.
{
    path: "/login",
    name: "Login",
    component: LoginView,
},
.
.

3、新建 components/auth/LoginView.vue 组件并请求登录接口,添加代码:

<template>
  <div class="sign-in">
    <el-row>
      <el-col :span="12" :offset="6">
        <h1>长乐未央后台</h1>
        <el-form
          :model="user"
          :rules="rules"
          ref="ruleForm"
          label-width="100px"
          class="demo-ruleForm"
        >
          <el-form-item label="用户名" prop="username">
            <el-input v-model="user.username"></el-input>
          </el-form-item>
          <el-form-item label="密码" prop="password">
            <el-input v-model="user.password" type="password"></el-input>
          </el-form-item>
          <el-form-item>
            <el-button type="primary" @click="submitForm('ruleForm')">
              立即登录
            </el-button>
            <el-button @click="resetForm('ruleForm')">重置</el-button>
          </el-form-item>
        </el-form>
      </el-col>
    </el-row>
  </div>
</template>

<script>
import { userLogin } from "@/api/auth";

export default {
  data() {
    return {
      user: {
        username: "",
        password: "",
      },
      rules: {
        username: [{ required: true, message: "请输入用户名", trigger: "blur" }],
        password: [{ required: true, message: "请输入密码", trigger: "blur" }],
      },
    };
  },
  methods: {
    submitForm(formName) {
      this.$refs[formName].validate((valid) => {
        if (valid) {
          userLogin(this.user).then((res) => {
            if (res.code === 20000) {
              localStorage.token = res.data.token;
              location.reload();
            } else {
              this.$message.error(res.message);
            }
          });
        }
      });
    },
    resetForm(formName) {
      this.$refs[formName].resetFields();
    },
  },
};
</script>

<style>
.sign-in {
  padding-top: 100px;
}

h1 {
  text-align: center;
}
</style>

4、封装 axios 拦截器,前台验证 token

utils/request.js 中,添加代码:

.
.
// 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);
  }
);
.
.

5、判断是否登录,在 App.vue 中修改代码:

<template>
  <Login v-if="!token" />
  <el-container v-else>
    <el-header>
      <img
        src="https://images.clwy.cn/common/logo.png"
        alt="长乐未央Logo"
        class="logo"
      />
      <h1>长乐未央后台管理</h1>
    </el-header>
    <el-container>
      <el-aside width="200px">
        <Menu />
      </el-aside>
      <el-container>
        <el-main>
          <router-view />
        </el-main>
        <el-footer>
          Copyright 2013-2022 CLWY Inc. All Rights Reserved.
        </el-footer>
      </el-container>
    </el-container>
  </el-container>
</template>

<script>
import Menu from "@/components/layouts/MenuComponent";
import Login from "@/components/auth/LoginView";
export default {
  components: {
    Menu,
    Login,
  },
  data() {
    return {
      token: "",
    };
  },
  created() {
    this.token = localStorage.token;
  },
};
</script>

至此,前端验证 token 工作已完成,测试结果:未登录状态下,访问后台请求接口的页面是无法访问的。当用户登录成功后,即 token值存在的情况下,可正常访问。

但是我们会发现一个严重的问题,只要 token 值存在,不管对错与否,都能登录后台,这样用户就可以恶意篡改 token 的值,网站不安全!

5、继续封装 axios 拦截器,后台验证 token

这里需要注意的是如果后端接口验证的中间件没写,要自行加上。

utils/request.js 中,添加代码:

.
.
import { MessageBox, Message } from "element-ui";
.
.
// response拦截器
service.interceptors.response.use(
  /**
   * 如果你想获取 http 信息,例如 headers 或 status
   * 请 return  response => response
   */

  /**
   * 下面的注释为通过response自定义code来标示请求状态,当code返回如下情况为权限有问题,登出并返回到登录页
   * 如通过xmlhttprequest 状态码标识 逻辑可写在下面error中
   */
  (response) => {
    const res = response.data;

    // 如果返回的自定义code不是20000, 认定为error。
    if (res.code !== 20000) {
      Message({
        message: res.message || "Error",
        type: "error",
        duration: 5 * 1000,
      });

      // 50008:非法的token; 50012:其他客户端登录了;  50014:Token 过期了;
      if (res.code === 50008 || res.code === 50012 || res.code === 50014) {
        // 重新登录
        MessageBox.confirm(
          "你已被登出,可以取消继续留在该页面,或者重新登录",
          "确定登出",
          {
            confirmButtonText: "重新登录",
            cancelButtonText: "取消",
            type: "warning",
          }
        ).then(() => {
          // 为了重新实例化vue-router对象 避免bug
          localStorage.removeItem("token");
          location.reload();
        });
      }
      return Promise.reject(new Error(res.message || "Error"));
    } else {
      return res;
    }
  },
  (error) => {
    console.log("err" + error); // for debug
    Message({
      message: error.message,
      type: "error",
      duration: 5 * 1000,
    });
    return Promise.reject(error);
  }
);
.
.

接下来测试,当用户在浏览器中修改了一个错误的 token 值,发现无法正常登录了,这就是后端验证了 token 是否正确。

6、假设现在是已登录状态,当用户直接在浏览器中输入登录的路由,直接就进入登录页面了,这样用户体验就不太好了

router/index.js

// 路由守卫
router.beforeEach((to, from, next) => {
  const token = localStorage.token;

  if (token) {
    // 如果已经登录了,自己非要手动访问登录页,则自动跳转到首页
    if (to.path === "/login") {
      next({ path: "/" });
    }
    next();
  } else {
    next({
      path: "/login",
    });
  }
});

sessionStorage 的用法

存储方式:sessionStorage.token = xxx,用法跟 localStorage 一样的。但是两者是有一定区别的!

localStorage可以永久存储数据,而sessionStorage当浏览器关闭后,数据丢失!

一张图看懂 token 的作用,如图所示:

请添加图片描述

总结:登录业务流程

1、在登录页输入用户名和密码
2、点击登录按钮,调用后台登录接口,请求成功后得到 token,并存入 localStorage
3、根据后台的响应状态跳转到后台首页

  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值