谈谈对登录逻辑的理解

 

谈谈对登录逻辑的理解

登录逻辑

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信息并跳转到登录页面

具体步骤:

1、在vue项目中,找到src文件夹下的views文件夹,并在里面创建一个login文件夹(为了方便管理与维护),在里面创建Login.vue模板文件

2、在Login.vue中配置登录需求(在这里用的是vant组件库)

<template>
  <div class="login_container">
     <van-nav-bar
      title="登录"
      left-arrow
      @click-left="onClickLeft"
    />
    <div class="login_from">
      <van-form>
        <van-field
          v-model="username"
          name="手机号"
          placeholder="请输入手机号"
        >
        </van-field>
        <van-field
          v-model="password"
          type="password"
          name="密码"
          placeholder="请输入密码"
        />
        <div style="margin: 0.8rem; margin-top: 1rem">
          <van-button round block type="warning" @click="onSubmit">
            登录
          </van-button>
        </div>
      </van-form>
    </div>
  </div>
</template>

<script>
import Vue from 'vue'
import { Toast } from "vant"; //引入文字提示
Vue.use(Toast);
export default {
  data() {
    return {
      username: "",//用户名
      password: "",//密码
    };
  },
  methods: {
    onClickLeft(){//点击返回上一页
        this.$router.go(-1);
    },
    onSubmit(values) {
      //点击登录
      // console.log("submit", values);
        //首先判断用户名和密码不能为空,如果为空就不提交请求
      if (this.username.length == 0 || this.password == 0) {
        Toast({
          message: "输入的手机号或密码不能为空!!!",
          position: "top",
        });
        return;
      }
      // 请求登录接口并配置参数
      this.$axios.get("xxxxx",{params:{
            username:this.username
            password:this.password
        })
        .then((res) => {
          // 请求成功,返回
          console.log(res);
          // 如果请求成功,服务器会返回一个token,我们要保存token
          var token = res.data.token; //读取token
          localStorage.setItem("token", token); //保存token
          // 登录成功的提示
          Toast.success({
            message: "登录成功",
            position: "top",
          });
           // 最后跳转页面
          this.$router.push("/"); //跳转到首页
        })
        .catch((err) => {
            // 请求失败,返回
          console.log(err);
            // 登录失败的提示
          Toast.fail({
            message: "登录失败",
            position: "top",
          });
        });
    }
  },
};
</script>

<style lang="scss" scoped>
.login_container {
  width: 100%;
  height: 100vh;
}
.login_from {
  width: 95%;
  margin: 0 auto;
}
</style>

3、在配置全局路由守卫(在router文件夹下的index.js文件中配置),只有先登录后才能进入其他页面

// 导航守卫
// 使用 router.beforeEach 注册一个全局前置守卫,判断用户是否登陆
// to: route路由对象 即将进入的目标路由
// from: route路由对象 当前导航正要离开的路由
// next: function函数  一定要调用这个函数来resolve这个钩子(放行函数)
router.beforeEach((to, from, next) => {
  if (to.path === '/login') {//判断是否是进入登录页面,如果是直接放行
    next();
  } else {//如果不是,判断是否存在token
    let token = localStorage.getItem('token');
 
    if (token) {//如果有token,就直接放行
      next();
    } else {//如果没有token,就去登录页面
      next('/login');
    }
  }
});

4、在组件中发送请求需要携带token,这样做主要是:用来作身份验证

4.1、我们需要新建一个request.js文件,在里面先引入axios模块,在创建axios实例

import axios from "axios";//引入axios模块
import API from "config.js";//引入请求类型
// import Vue from 'vue';
import { Toast } from 'vant';
import {Guid} from "./guid";//引入这个guid.js文件可以自动获取设备id

var id = localStorage.getItem("deviceid");//先读取
let deviceid = null;
if(id){
  deviceid = id
}else{
  deviceid = Guid.NewGuid().ToString("D");
}
localStorage.setItem("deviceid",deviceid)

// 创建实例
const instance = axios.create({
  baseURL: 'http://xxxxx',//公用路径
  timeout: 6000,//设置超时时间
});


//   拦截器
// 添加请求拦截器
instance.interceptors.request.use(function (config) {
    // 在发送请求之前做些什么
    //弹起loading控件
    Toast.loading({
      duration:0,
      message: '加载中...',
      forbidClick: true,
    });
    //读取token
    var token = localStorage.getItem("token");
    if(token){//容错判断
        //在请求头中添加token
      config.headers.authorization = `Bearer ${token}`;
    }
    //在请求头中添加设备id
    config.headers.deviceid = deviceid;
    config.headers.devicetype = "H5";
    return config;
  }, function (error) {
    // 对请求错误做些什么
    return Promise.reject(error);
  });

// 添加响应拦截器
instance.interceptors.response.use(function (response) {
    // 对响应数据做点什么
    // 关闭loading控件
    Toast.clear();
    return response;
  }, function (error) {
    // 对响应错误做点什么
    return Promise.reject(error);
  });

//   判断是get请求还是post请求
export function requset(type, url, params) {
  switch (type) {
    case API.type.GET:
      return get(url, params);
    case API.type.POST:
      return post(url, params);
  }
}


//   封装get请求
function get(url, params) {
  return instance.get(url, params);
}

// 封装post请求
function post(url, params) {
  return instance.post(url, params);
}

4.2、在创建一个config.js的文件

const API = {
    // 配置API路径
    url: {
        // 例如:
        // 轮播图
        Banner: "/xxxxx",
    },
    type: {
        GET: "get",//请求类型get请求
        POST: "post",//请求类型post请求
    }
}
export default API;

4.3、在创建一个index.js文件

import { requset } from "./core";
import API from "./config";//引入请求参数

const ClientAPI = {
    // 封装请求函数(方法)
    // 轮播图
   //banner() {
       // return requset(API.type.GET, API.url.Banner)
   // },

}
export default ClientAPI;

4.4、在创建一个guid.js文件

//表示全局唯一标识符 (GUID)。
function Guid(g) {
    var arr = new Array(); //存放32位数值的数组

    if (typeof (g) == "string") { //如果构造函数的参数为字符串

        InitByString(arr, g);

    } else {
        InitByOther(arr);
    }

    //返回一个值,该值指示 Guid 的两个实例是否表示同一个值。

    this.Equals = function (o) {

        if (o && o.IsGuid) {

            return this.ToString() == o.ToString();

        } else {

            return false;

        }

    }

    //Guid对象的标记

    this.IsGuid = function () { }

    //返回 Guid 类的此实例值的 String 表示形式。

    this.ToString = function (format) {

        if (typeof (format) == "string") {

            if (format == "N" || format == "D" || format == "B" || format == "P") {

                return ToStringWithFormat(arr, format);

            } else {

                return ToStringWithFormat(arr, "D");

            }

        } else {

            return ToStringWithFormat(arr, "D");

        }

    }

    //由字符串加载

    function InitByString(arr, g) {

        g = g.replace(/\{|\(|\)|\}|-/g, "");

        //g = g.toLowerCase();

        if (g.length != 32 || g.search(/[^0-9,a-f]/i) != -1) {

            InitByOther(arr);

        } else {

            for (var i = 0; i < g.length; i++) {

                arr.push(g[i]);

            }

        }

    }

    //由其他类型加载

    function InitByOther(arr) {

        var i = 32;

        while (i--) {

            arr.push("0");

        }

    }

    /*

    根据所提供的格式说明符,返回此 Guid 实例值的 String 表示形式。

    N  32 位: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

    D  由连字符分隔的 32 位数字 xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx

    B  括在大括号中、由连字符分隔的 32 位数字:{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}

    P  括在圆括号中、由连字符分隔的 32 位数字:(xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx)

    */

    function ToStringWithFormat(arr, format) {
        let str;
        switch (format) {

            case "N":

                return arr.toString().replace(/,/g, "");

            case "D":

                str = arr.slice(0, 8) + "-" + arr.slice(8, 12) + "-" + arr.slice(12, 16) + "-" + arr.slice(16, 20) + "-" + arr.slice(20, 32);

                str = str.replace(/,/g, "");

                return str;

            case "B":

                str = ToStringWithFormat(arr, "D");

                str = "{" + str + "}";

                return str;

            case "P":

                str = ToStringWithFormat(arr, "D");

                str = "(" + str + ")";

                return str;

            default:

                return new Guid();
        }
    }
}

//Guid 类的默认实例,其值保证均为零。

Guid.Empty = new Guid();

//初始化 Guid 类的一个新实例。

Guid.NewGuid = function () {
    var g = "";

    var i = 32;

    while (i--) {

        g += Math.floor(Math.random() * 16.0).toString(16).toUpperCase();

    }

    return new Guid(g);
}

export { Guid };

4.5、在mian.js文件中引入,最后注册下

import Vue from 'vue'
import './plugins/axios'
import App from './App.vue'
import router from './router'
import store from './store'
import './plugins/vant.js'
import "./rem/rem.js";//引入rem
import ClientAPI from "./api/index";//引入封装的api
Vue.prototype.$ClientAPI = ClientAPI;//全局注册
Vue.config.productionTip = false;

new Vue({
  router,
  store,
  render: h => h(App)
}).$mount('#app')

5、在组件中使用

<script>
export default {
  name: "",
  data() {
    return {
        banner:[],//轮播图数据
    };
  },
  mounted() {
    //在组件中使用
    //请求轮播图数据
    this.$ClientAPI.banner().then(res=>{
         console.log(res);
    }).catch(err=>{
        console.log(err);
    })
  },
  methods: {
   
  },
};
</script>

 

  • 5
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
对数据库系统的认识 这学期我们开了数据库系统这门课,开课近五周的时间,虽然只学习到第二章,但 是从绪论中我就已经感受到了数据库的强大,有关数据库的内容老师也给我们讲解了很 多,接下来我想来谈谈我对数据库的认识,还望老师批评指正。 我们都知道数据库是数据管理的最新技术,是计算机科学的重要分支。而且对于一个国家 来说,数据库的建模,数据库信息量的大小和使用频度的已成为衡量这个国家信息化程 度的高低的重要标志。所以,数据库系统这门2课时及其重要的,学好它很必要。 数据库最常用的术语有数据(Data)、数据库(DB)、数据库管理系统(DBMS)、数据 库系统(DBS)等,以下是我对它们的理解: 数据(Data):数据是数据库中存储的基本对象。数据的种类很多,文字,图形,图 像,声音,学生的档案记录,货物的运输情况等,这些都是数据。可以对数据做如下定 义:描述事物的符号记录称为数据; 数据库(DB):数据库,顾名思义,是存放数据的仓库。只不过这个仓库是在计算机 存储设备上,而且数据是按一定的格式存放的。所谓数据库是指长期存储在计算机内的 ,有组织的,可共享的数据集合; 数据库管理系统(DBMS):数据库管理系统是位于用户与操作系统之间的一层数据 管理软件。它的主要功能包括:数据定义功能,数据操纵功能,数据库的运行管理,数 据库的建立和维护功能等; 数据库系统(DBS):数据库系统是指在计算机系统中引入数据库后的系统,一般由 数据库,数据库管理系统,应用系统,数据库管理原和用户构成。 数据库管理技术的产生和发展共经历了三个阶段:人工管理阶段(20世纪50年代中 期以前),文件系统阶段(20世纪50年代后期到60年代中期),数据库系统阶段(20世 纪60年代后期以后)。其特点经历了从数据不能保存,不能共享,不具有独立性,到数 据结构化,共享性高,冗余度低,易扩充,独立性高,由DBMS统一管理和控制的逐步优 化。 数据模型分为两类,一类是概念模型,主要用于数据库设计,一类是逻辑模型和物 理模型,主要用于DBMS的实现。数据模型通常由数据结构、数据操作和完整性约束三部 分组成。 数据库系统的三级模式结构是指数据库系统是由外模式、模式和内模式三级组成, 数据库管理系统在这三级模式之间还提供了两层映像,这样的系统结构保证了数据库系 统中能够具有较高的逻辑独立性和物理独立性。 通过对这些内容的学习,我深刻认识到作为一名计算机专业的学生学好这门课的重 要性与必要性,在接下来的学习中,更会严格要求自己,紧跟老师步伐,下课多加复习 ,遇到不懂的问题将会及时查阅资料或者向老师同学请教。 ----------------------- 对数据库系统的认识全文共2页,当前为第1页。 对数据库系统的认识全文共2页,当前为第2页。
   1. struts是一个按MVC模式设计的Web层框架,其实它就是一个大大的servlet,这个Servlet名为ActionServlet,或是ActionServlet的子类。我们可以在web.xml文件中将符合某种特征的所有请求交给这个Servlet处理,这个Servlet再参照一个配置文件(通常为/WEB-INF/struts-config.xml)将各个请求分别分配给不同的action去处理。    一个扩展知识点:struts的配置文件可以有多个,可以按模块配置各自的配置文件,这样可以防止配置文件的过度膨胀;    2. ActionServlet把请求交给action去处理之前,会将请求参数封装成一个formbean对象(就是一个java类,这个类中的每个属性对应一个请求参数),封装成一个什么样的formbean对象呢?看配置文件。    3.要说明的是, ActionServlet把formbean对象传递给action的execute方法之前,可能会调用formbean的validate方法进行校验,只有校验通过后才将这个formbean对象传递给action的execute方法,否则,它将返回一个错误页面,这个错误页面由input属性指定,(看配置文件)作者为什么将这里命名为input属性,而不是error属性,我们后面结合实际的运行效果进行分析。    4.action执行完后要返回显示的结果视图,这个结果视图是用一个ActionForward对象来表示的,actionforward对象通过struts-config.xml配置文件中的配置关联到某个jsp页面,因为程序中使用的是在struts-config.xml配置文件为jsp页面设置的逻辑名,这样可以实现action程序代码与返回的jsp页面名称的解耦。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值