5.单点登录(Vue2.x)

概况

百度百科

单点登录(Single Sign On),简称为 SSO,是比较流行的企业业务整合的解决方案之一。SSO的定义是在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统。

关键词

tokensessioncookie统一的认证系统

流程说明

这里将 一期 系统比喻主系统,二期 系统使用(跳转到) 一期 系统的登录认证。

  1. 打开二期主页,当没有登录权限token,跳转到一期登录页。并在跳转的 url 中带上二期 url,用于登录成功后跳回二期。
    在这里插入图片描述

    2.在 一期 登录成功后,url 中带上参数 token 并返回到 二期 系统;

在这里插入图片描述

  1. 在新窗口中打开 一期 主页,默认已登录。点击 “注销” (此时向后台接口发请求注销 token,并 删除相关Cookie信息),返回登录页;
  2. 当在新窗口中打开二期页或刷新页面,调相关接口token验证接口。如果接口返回http 401,则token已失效。此时会返回一期登录页,重新登录(即图一)。

在这里插入图片描述

代码实现

注意要安装插件 js-cookie

npm i js-cookie

公共方法,一期和二期都有使用。解析

function getParamFromUrl() {
  let url = location.href;
  let map = {}
  let paramsStr = url.split('?')[1]
  if (paramsStr) {
      let paramStrList = paramsStr.split('&')
      for (let i = 0; i < paramStrList.length; i++) {
          let param = paramStrList[i].split('=')
          map[param[0]] = param[1]
      }
  }
  return map;
}

cookie Id,注意一期和二期同名。

const tokenCookieId = 'user_token';

二期

config.js
// 一期API服务地址
const ApiUrl  = 'http://192.168.182.243:8088/';
// 一期登录页面
const LoginUrl = "http://192.168.182.243:8088/login"
main.js

先判断是否有token

import Cookie from 'js-cookie'

// 解析 url 参数
let token = getParamFromUrl().token;

// url 是否带有 token
if (token) {
      Cookie.set(tokenCookieId, params.token);
      init(token);
} else {// Cookie 中能否找到 token
      token = Cookie.get(tokenCookieId);
      init(token);
}

初始化方法,判断是否有 token

  1. 没有 token,则直接跳转登录;
  2. token,验证 token 是否有效,无效则直接跳转登录。**有效*则进入系统;
import axios from 'axios'

function init(token) {
  if (token) {    
    let newAxios = axios.create({
      baseURL: ApiUrl,
      headers: { 'Authorization': token.replace('%20', ' ') }
    })
    // 获取用户信息,同时验证 token 是否有效
    newAxios.get(`/api/user/myinfo`).then((response) => {
      store.commit('user/SET_NAME', {
        userName: response.data.username,
        isManager: response.data.manager
      })
      // 注意:此时在初始化 Vue 主页
      return new Vue({
        el: '#app',
        router,
        store,
        render: h => h(App)
      })
    })
    .catch((error) => {
        // 一般会返回 401,token失效。移除 Cookie 中的 token,
        Cookie.remove(tokenCookieId);
        // 跳转到一期去登录,注意带上本页的 url,用于跳回
        location.href = LoginUrl + "?redirect=" + location.origin;
    })
  } else {// 根本就没有 token,一般为首次打开系统页面
      Cookie.remove(tokenCookieId);
      location.href = LoginUrl + "?redirect=" + location.origin;
  }
}

一期

router/index.js

路由前置守卫(全局) router.beforeEach

router.beforeEach((to, from, next) => {
  	let redirUrl = getParamFromUrl().redirect;
  	// Vuex store 也是从 Cookie 中获取,这里是项目截取,也可直接使用 Cookie.get
  	store.commit('user/REFRESH_NAME');
  	// 判断是否有 token  
  	if (store.state.user.token) {
      	// 是否有重定向 url,有则说明是从二期系统发来的请求。带上token返回到一期系统
    	if(redirUrl) {
      		location.href = redirUrl+'?token='+store.state.user.token
    	}
    	else if (to.path == '/login') {
      		next('/first')
    	}
        else {
              let pages = ''
              if(store.state.user.pages){
                pages = store.state.user.pages.split(',')
              }  
              if (store.state.user.isManager) {
                next()
              }
              else if (authorPages.indexOf(to.path) == -1) {
                	next()
              }
              else if (pages.indexOf(to.path ) > -1) {
                	next()
              } 
              else {
                	next('/noAuthor')
              }
        }
      } else {
            if(redirUrl) {// 没token 且从二期发来的请求,直接进入登录页即可
              	next()
            }
            else if (authorPages.indexOf(to.path) == -1){
              	next()
            }
            else if(to.path == '/login') {
              	next()
            }
            else {
              	next('/login')
            }
      }
})
App.vue

mounted 方法

mounted () {
    // 二期url
    let redirectUrl = getParamFromUrl().redirect;
    let token = Cookie.get(tokenCookieId);
    if (redirectUrl && token) {// 有 redirect 和 token 就返回到二期
      	location.href = decodeURIComponent(redirectUrl) + "?token=" + token;
    }
    else{// 一期,说明直接从一期打开。如下操作为可选项,如获取用户信息
      	let url = `/api/user/myinfo`;
      	this.$axios.get(url).then((response) => {
        	this.$store.commit('user/SET_NAME', {
          		userName: response.data.username,
          		isManager: response.data.manager
        	})
      	})
      	.catch((error) => {
        	this.$store.dispatch('user/logout');
        	if (!redirectUrl) {// 不是从二期进入,则直接去登录
          		this.$router.push('/login')
        	}
      	})
    }
}
store/modules/user.js

logout登出方法,删除相关 Cookie

const actions = {
  logout ({ commit }) {
    Cookies.remove('user_name')
    Cookies.remove('user_token')
    Cookies.remove('user_isManager')
    mutations.REFRESH_NAME(state)
  }
}
views/login.vue

登录时,如果有 redirect,则是从二期跳转过来的。

commit () {
  	if (this.inputName.trim() == '' || this.inputPw.trim() == '') {
    	this.$message({ type: 'error', message: '请输入用户名密码!' });
    	return;
  	}
  	let form = {
    	userName: this.inputName,
    	password: md5(this.inputPw),
  	}
  	// 登录请求
  	let navUrl = 'api/user/login'
  	this.$axios.post(navUrl, form).then((resp) => {
      	if (resp.data.success) {
        	let token = resp.data.token;
        	this.$store.commit('user/SET_TOKEN', token);
        	// 是否为二期请求
        	let redirectUrl = getParamFromUrl().redirect;
        	if (redirectUrl) {// 是二期请求,带着 token 跳转回去
          		location.href = decodeURIComponent(redirectUrl) + "?token=" + token;
        	} else {// 不是,则进入一期系统
          		location.reload()
        	}
      	} else {
        	this.$message({ type: 'error', message: resp.data.message })
      	}
    })
    .catch((error) => {
      	this.$message({ type: 'error', message: error })
    })
},
TopHeader.vue 和 Adminbox.vue

注销时一定要调后台接口,真正是注销服务端的 token。

// 清除用户相关信息
this.$store.dispatch("user/logout");
// 跳转到登录页
this.$router.push('/login');
// 调服务接口的注销方法,真正注销
this.$axios.get('api/user/logout').then((r)=>{
    console.log('注销成功');
}).catch(e=> {
    console.error(e);
})
  • 1
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
【资源说明】 1、基于SpringBoot+Vue开发的前后端分离外卖点单系统源码+数据库+项目说明.zip 2、该资源包括项目的全部源码,下载可以直接使用! 3、本项目适合作为计算机、数学、电子信息等专业的课程设计、期末大作业和毕设项目,作为参考资料学习借鉴。 4、本资源作为“参考资料”如果需要实现其他功能,需要能看懂代码,并且热爱钻研,自行调试。 基于SpringBoot+Vue开发的前后端分离外卖点单系统源码+数据库+项目说明.zip 基于SpringBoot+Vue开发的前后端分离外卖点单系统源码+数据库+项目说明.zip ## 目录结构 后台前端项目位于renren-ui下 小程序前端项目位于takeout_mp下 SQL文件位于根目录下的takeout_mysql8.sql,需要MYSQL8以上版本。 **ps:请先运行后端项目,再启动前端项目。** ``` take_out │ ├─renren-admin 美食元素后台管理后端服务 │ │ │ │ │ ├─modules 模块 │ │ ├─job 定时任务 │ │ ├─log 日志管理 │ │ ├─oss 文件存储 │ │ ├─security 安全模块 │ │ ├─sys 系统管理(核心) | | └─takeout 外卖业务模块(核心) │ │ │ └─resources │ ├─mapper MyBatis文件 │ ├─public 静态资源 │ └─application.yml 全局配置文件 │ │ ├─renren-api 美食元素小程序后端服务 │ ├─renren-common 公共模块 ├─renren-generator 代码生成器 │ └─resources │ ├─mapper MyBatis文件 │ ├─template 代码生成器模板(可增加或修改相应模板) │ ├─application.yml 全局配置文件 │ └─generator.properties 代码生成器,配置文件 │ ├─renren-ui 美食元素后台管理Vue前端项目 ├─takeout_mp uniapp微信小程序项目 ``` ## 项目特点 - 友好的代码结构及注释,便于阅读及二次开发 - 实现前后端分离,通过token进行数据交互 - 支持动态权限修改,采用RBAC模型,前端菜单和后台权限实时更新。 - 提供CrudService接口,对增删改查进行封装,代码更简洁 - 页面交互使用Vue2.x,极大的提高了开发效率 - 完善的部门管理及数据权限,通过注解实现数据权限的控制 - 完善的XSS防范及脚本过滤,彻底杜绝XSS攻击 - 完善的代码生成机制,可在线生成entity、xml、dao、service、vue、sql代码,减少70%以上的开发任务 - 引入quartz定时任务,可动态完成任务的添加、修改、删除、暂停、恢复及日志查看等功能 - 引入Hibernate Validator校验框架,轻松实现后端校验 - 引入云存储服务,已支持:七牛云、阿里云、腾讯云等 - 引入swagger文档支持,方便编写API接口文档 - 新增AOP注解实现日志管理。 - 代码遵循阿里巴巴开发规范,利于开发者学习。 ## 技术选型 - 核心框架:Spring Boot 2.7.1 - 安全框架:Apache Shiro 1.9 - 持久层框架:MyBatis 3.5 - 定时器:Quartz 2.3 - 数据库连接池:Druid 1.2 - 日志管理:Logback - 页面交互:Vue2.x - 微信小程序:uni-app ## 开发环境 | 开发工具 | 说明 | | ----------------------------- | ------------------ | | IDEA | Java开发工具IDE | | WebStrom或者VS Code | Vue开发工具IDE | | Navicat | MySQL远程连接工具 | | Another Redis Desktop Manager | R
好的,以下是一个简单的外卖点单页面的 Vue 代码示例: ```html <template> <div> <h2>外卖点单</h2> <div v-for="item in items" :key="item.id"> <h3>{{ item.name }}</h3> <p>{{ item.description }}</p> <p>价格:{{ item.price }}元</p> <button @click="addToCart(item)">加入购物车</button> </div> <h2>购物车</h2> <div v-if="cartItems.length === 0"> <p>购物车是空的</p> </div> <ul v-else> <li v-for="item in cartItems" :key="item.id"> {{ item.name }} x{{ item.quantity }} = {{ item.price * item.quantity }}元 <button @click="removeFromCart(item)">移除</button> </li> </ul> <p>总价:{{ totalPrice }}元</p> <button @click="checkout">结算</button> </div> </template> <script> export default { data() { return { items: [ { id: 1, name: '红烧牛肉面', description: '牛肉面配上浓郁的红烧汤底', price: 18 }, { id: 2, name: '香辣小龙虾', description: '麻辣鲜香,口感鲜美', price: 58 } ], cartItems: [], totalPrice: 0 }; }, methods: { addToCart(item) { const existingItem = this.cartItems.find(cartItem => cartItem.id === item.id); if (existingItem) { existingItem.quantity++; } else { this.cartItems.push({ ...item, quantity: 1 }); } this.totalPrice += item.price; }, removeFromCart(item) { const index = this.cartItems.indexOf(item); if (index !== -1) { const cartItem = this.cartItems[index]; this.totalPrice -= cartItem.price * cartItem.quantity; this.cartItems.splice(index, 1); } }, checkout() { alert(`您需要支付${this.totalPrice}元`); } } }; </script> ``` 这个代码示例包括了外卖点单的基本功能,包括商品列表、加入购物车、移除购物车、计算总价和结算等。你可以根据自己的需要进行修改和扩展。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值