基于Oauth2的SSO单点登录---前端

Vue-element-admin 是一个基于 Vue.js 和 Element UI 的后台管理系统框架,提供了丰富的组件和功能,可以帮助开发者快速搭建现代化的后台管理系统。

一、基本知识

(一)Vue-element-admin 的主要文件和目录

vue-element-admin/
|-- build/ # 构建相关配置文件
| |-- build.js # 生产环境构建脚本
| |-- check-versions.js # 检查 Node.js 和 npm 版本的脚本
| |-- logo.png # 构建 Logo
| |-- utils.js # 构建工具函数
| |-- vue-loader.conf.js # Vue loader 配置
| |-- webpack.base.conf.js # webpack 基础配置
| |-- webpack.dev.conf.js # webpack 开发环境配置
| |-- webpack.prod.conf.js # webpack 生产环境配置
|
|-- config/ # 项目配置
| |-- dev.env.js # 开发环境变量配置
| |-- index.js # 项目配置文件
| |-- prod.env.js # 生产环境变量配置
|
|-- src/ # 源代码
| |-- api/ # 接口请求相关
| |-- assets/ # 静态资源
| |-- components/ # 全局公用组件
| |-- directive/ # 自定义指令
| |-- icons/ # 图标
| |-- layout/ # 全局布局
| |-- router/ # 路由配置
| |-- store/ # 全局状态管理
| |-- styles/ # 全局样式
| |-- utils/ # 工具函数
| |-- views/ # 页面组件
| |-- App.vue # 入口页面
| |-- main.js # 入口 JS 文件

| |-- permission.js # 路由守卫 文件
|
|-- static/ # 静态资源
|
|-- .babelrc # Babel 配置
|-- .editorconfig # 编辑器配置
|-- .eslintignore # ESLint 忽略文件配置
|-- .eslintrc.js # ESLint 配置
|-- .gitignore # Git 忽略文件配置
|-- index.html # 入口 HTML 文件
|-- package.json # 项目信息和依赖配置
|-- README.md # 项目说明文档
|-- vue.config.js # Vue CLI 配置

(二)单点登录系统涉及的文件和概念

  1. **客户端ID和客户端密钥:**前端应用和后端应用在与单点登录系统通信时,需要提供客户端ID和客户端密钥进行身份验证。
  2. **授权码(authorization code):**单点登录系统验证用户身份成功后生成的一次性授权码,用于换取访问令牌和刷新令牌。
  3. **访问令牌(access token):**单点登录系统验证成功后返回给前端应用的令牌,用于后续请求时进行身份验证。
  4. **刷新令牌(refresh token):**单点登录系统验证成功后返回给前端应用的令牌,用于在访问令牌过期时更新访问令牌。
  5. **前端应用使用的SDK或库文件:**前端应用需要集成相应的SDK或库文件以便与单点登录系统进行通信。
  6. **单点登录系统的API文档:**开发人员需要根据API文档了解单点登录系统提供的接口和参数,以便正确调用API接口。

二、 前端实现单点登录的基本流程

**设计思路:**为了避免code和access_token的泄露,所以大部分的和单点登录系统(统一认证)的交互都放到后端进行,前端尽可能的复用原来的代码,进行小的改动。整体思路如下:

****1、登录页面–login.vue(修改原login.vue)😗***用户访问前端应用,前端应用将用户重定向到后端登录接口。

<template><div class="login-container"><div>正在重定向到登录页面...</div></div>
</template><script>
export default {created() {const baseUrl = process.env.VUE_APP_BASE_API;//重定向到后端的SSOlogin/login接口window.location.href = `${baseUrl}/SSOlogin/login`;},
};
</script><style scoped>
.login-container {display: flex;justify-content: center;align-items: center;height: 100vh;text-align: center;
}
</style>

****2、 响应页面–callback.vue(新建)😗***检查后端返回的URL+token访问链接中是否存在后端返回的token,如果存在则调用登录函数user/login进行前端的登录操作(调用login函数进行前端的登录,目的是将token持久化和存储到VUEX中,尽可能少的改动原来的代码。),并根据登录结果进行不同的处理。如果没有获取到token,则输出错误信息并终止后续逻辑。

<template><div><h1>Loading...</h1></div>
</template><script>
export default {name: "Callback",data() {return {};},created() {// 获取 URL 查询参数中的授权码const token = this.$route.query.token;// 利用后端传递的token,调用login函数进行前端的登录,目的是将token持久化和存储到VUEX中,尽可能少的改动原来的代码if (token) {this.loading = true;this.$store.dispatch("user/login",token).then(() => {// 登录成功,路由跳转this.$router.push({ path: this.redirect || "/" });this.loading = false;}).catch(() => {this.loading = false;});} else {console.log("error submit!!");return false;}},
};
</script>

对应的store/user.js。

3、 数据仓库 store/user.js,修改一下原来的Login函数即可。

原Login函数为:

//这里在处理登录业务async login({ commit }, userInfo) {//解构出用户名与密码const { username, password } = userInfo;let result = await login({ username: username.trim(), password: password });if(result.code==200){//vuex存储tokencommit('SET_TOKEN',result.data.token);//本地持久化存储tokensetToken(result.data.token);return 'ok';}else{return Promise.reject(new Error('faile'));}},

修改后的Login为:

 // 登录 actionasync login({ commit }, token) {try {// 设置 token 持久化commit('SET_TOKEN', token);// 将 token 值保存在浏览器的本地存储中setToken(token);// 可以根据需要返回其他数据或状态return "ok";} catch (error) {// 异常时返回一个被拒绝的 Promise 对象return Promise.reject(error);}},

所以,修改login函数,去掉了使用用户名和密码发送请求到后端接口验证登录,完整的代码如下:

// 引入需要使用的函数和模块
import { getInfo, logout  } from '@/api/user'
import { getToken, setToken, removeToken } from '@/utils/auth'
import { resetRouter } from '@/router'// 定义获取默认状态的函数
const getDefaultState = () => {return {token: getToken(), // 使用 getToken 函数获取 token 值name: '',avatar: ''}
}// 定义 Vuex 模块的状态
const state = getDefaultState()// 定义 Vuex 模块的变更操作
const mutations = {// 重置状态为默认状态RESET_STATE: (state) => {Object.assign(state, getDefaultState())},// 设置 tokenSET_TOKEN: (state, token) => {state.token = token},// 设置用户名SET_NAME: (state, name) => {state.name = name},// 设置用户头像SET_AVATAR: (state, avatar) => {state.avatar = avatar}
}// 定义 Vuex 模块的异步操作
const actions = {// 用户登录// 登录 actionasync login({ commit }, token) {try {// 设置 tokencommit('SET_TOKEN', token);// 将 token 值保存在浏览器的本地存储中setToken(token);// 可以根据需要返回其他数据或状态return "ok";} catch (error) {// 异常时返回一个被拒绝的 Promise 对象return Promise.reject(error);}},async getInfo({ commit, state }) {try {// 发送请求获取用户信息const response = await getInfo(state.token)// 如果响应数据不存在,说明验证失败if (!response.data) {throw new Error('验证失败,请重新登录。')}// 获取用户名和头像const { name, avatar } = response.data// 设置用户名commit('SET_NAME', name)// 设置用户头像commit('SET_AVATAR', avatar)// 返回完整的响应对象return response} catch (error) {return Promise.reject(error)}},// 用户注销async logout({ commit, state }) {try {// 发送请求注销用户登录状态await logout(state.token)// 从本地存储中删除 tokenremoveToken()// 重置路由resetRouter()// 重置状态commit('RESET_STATE')} catch (error) {return Promise.reject(error)}},// 重置 token 值async resetToken({ commit }) {try {// 从本地存储中删除 tokenremoveToken()// 重置状态commit('RESET_STATE')} catch (error) {return Promise.reject(error)}}
}// 导出 Vuex 模块
export default {namespaced: true, // 开启命名空间state,mutations,actions
}

4、 数据仓库store/user.js引入的函数和模块

为了更清晰的了解整个过程,将上面store/user.js引入的函数和模块也贴在下面即:

因为 store/user.js中不用再向后端发请求,所以api/user.js中就可以把login删掉了。

api/user.js

//api/user.js
import request from '@/api/request/request'export function getInfo(token) {return request({url: '/user/getInfo',method: 'get',params: { token }})
}export function logout() {return request({url: '/user/logout',method: 'post'})
}

**utils/auth.js:**用于处理用户身份验证 token 的工具函数,主要涉及对浏览器 Cookie 的操作。getToken:获取用户的身份验证 token,setToken:设置用户的身份验证 token,removeToken:移除用户的身份验证 token。

//utils/auth.js
import Cookies from 'js-cookie'const TokenKey = 'vue_admin_template_token'export function getToken() {return Cookies.get(TokenKey)
}export function setToken(token) {return Cookies.set(TokenKey, token)
}export function removeToken() {return Cookies.remove(TokenKey)
}

5、路由守卫–permission.js:修改原来的)在每次路由导航之前进行身份验证和权限控制,确保用户在正确的身份状态下访问页面,并在页面切换后完成进度条的展示。

    如果用户已登录且获取了用户信息,则直接跳转到目标页面;如果用户未登录或获取用户信息失败,则跳转至登录页。同时,白名单内的页面可以在未登录状态下直接访问。

修改:配置白名单,把callback加进去

注意:通过 user/getInfo 获取用户信息 await store.dispatch(‘user/getInfo’),所以****api/user.js 里面要有getInfo函数。

permission.js 完整的代码如下:

import router from './router'
import store from './store'
import { Message } from 'element-ui'
import NProgress from 'nprogress' // 引入进度条库
import 'nprogress/nprogress.css' // 引入进度条样式
import { getToken } from '@/utils/auth' // 引入获取 token 的方法
import getPageTitle from '@/utils/get-page-title' // 引入获取页面标题的方法NProgress.configure({ showSpinner: false }) // 配置进度条const whiteList = ['/login','/callback'] // 定义无需登录即可访问的白名单路由router.beforeEach(async(to, from, next) => {NProgress.start() // 开始进度条document.title = getPageTitle(to.meta.title) // 设置页面标题const hasToken = getToken() // 获取 tokenif (hasToken) {if (to.path === '/login') {// 如果已登录却访问登录页,则重定向到首页next({ path: '/' })NProgress.done() // 完成进度条} else {const hasGetUserInfo = store.getters.name // 判断是否已获取用户信息if (hasGetUserInfo) {// 如果已获取,则直接进入路由next()} else {try {// 如果未获取,则通过 user/getInfo 获取用户信息await store.dispatch('user/getInfo')console.log("获取用户信息")next()} catch (error) {// 如果获取用户信息失败,则重置 token 并跳转至登录页await store.dispatch('user/resetToken')Message.error(error || 'Has Error')next(`/login?redirect=${to.path}`)// window.location.href = `www.baidu.com`;NProgress.done()}}}} else {if (whiteList.indexOf(to.path) !== -1) {// 如果在白名单中,则直接进入路由next()} else {// 否则跳转至登录页next(`/login?redirect=${to.path}`)NProgress.done()}}
})router.afterEach(() => {NProgress.done() // 完成进度条
})

6、请求拦截器中添加token到请求头:和原来一样)在请求拦截器中,从cookie中获取token,并将其添加到请求的头信息中,这样可以确保每次请求都带上了token。

import axios from 'axios'
import { MessageBox, Message } from 'element-ui'
import store from '@/store'
import { getToken } from '@/utils/auth'// 创建一个axios实例
const service = axios.create({baseURL: process.env.VUE_APP_BASE_API,  // 接口的基础路径timeout: 5000 // 请求超时时间
})// 请求拦截器
service.interceptors.request.use(config => {// 在请求发送前做一些处理if (store.getters.token) {// 如果有token就在请求头中加上tokenconfig.headers['token'] = getToken()}return config},error => {// 对请求错误做些什么console.log(error)return Promise.reject(error)}
)// 响应拦截器
service.interceptors.response.use(response => {// 对响应数据做一些处理,这里只返回响应数据中的data部分const res = response.data// 如果自定义的响应码不是20000,就判断为错误if (res.code !== 20000 && res.code !== 200) {// 在页面上显示错误信息Message({message: res.message || 'Error',type: 'error',duration: 5 * 1000})if (res.code === 50008 || res.code === 50012 || res.code === 50014) {// 重新登录MessageBox.confirm('您已经登出,您可以取消以留在此页面,或重新登录', '确认登出', {confirmButtonText: '重新登录',cancelButtonText: '取消',type: 'warning'}).then(() => {store.dispatch('user/resetToken').then(() => {location.reload()})})}// 返回一个被拒绝的Promise对象,用来表示错误return Promise.reject(new Error(res.message || 'Error'))} else {// 如果没有错误,就返回响应数据中的data部分return res}},error => {// 对响应错误做些什么console.log('err' + error)Message({message: error.message,type: 'error',duration: 5 * 1000})return Promise.reject(error)}
)export default service

**7、获取用户信息并渲染页面:**在需要展示用户信息的地方,从cookie中获取用户信息,并将其渲染到页面上。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/890912.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

linux内核如何实现TCP的?

TCP(传输控制协议)是网络通信中的核心协议之一,实现了可靠的、面向连接的、基于字节流的通信。在Linux内核中,TCP的实现相对复杂,涉及多个模块和层次。以下是一些关键概念和机制: 1. 协议栈 Linux 内核中的网络协议栈(Network Stack)是分层设计的,包括链路层、网络层…

ElasticSearch 分布式部署

一、引言 在当今大数据时代&#xff0c;数据呈爆炸式增长&#xff0c;如何高效地存储、检索数据成为了众多企业面临的关键挑战。ElasticSearch 作为一款强大的分布式搜索引擎&#xff0c;凭借其卓越的性能、灵活的扩展性以及强大的全文检索能力&#xff0c;在日志分析、数据分…

依图科技简介

依图科技&#xff08;YITU Technology&#xff09;是中国一家全球领先的人工智能&#xff08;AI&#xff09;公司&#xff0c;成立于2012年&#xff0c;总部位于上海。公司专注于计算机视觉、语音识别和自然语言处理等核心AI技术&#xff0c;致力于推动AI技术在医疗、安防、金融…

[创业之路-206]:《华为战略管理法-DSTE实战体系》- 6-关键成功因素法CSF

目录 一、概述 1、定义与起源 2、关键成功因素的定义 3、关键成功因素的来源 4、关键成功因素的确认方法 5、关键成功因素法的步骤 6、关键成功因素法的应用 7、关键成功因素法的优势与局限性 二、 关键成功因素法CSF的应用 1、企业战略管理 2、项目管理 3、绩效管…

Express.js 有哪些常用的中间件?

在使用 Express.js 开发应用程序时&#xff0c;中间件&#xff08;Middleware&#xff09;是处理请求和响应的关键组件。它们可以执行各种任务&#xff0c;如解析请求体、添加HTTP头部、记录日志等。以下是一些常用的中间件&#xff1a; body-parser 用于解析传入的请求体。它…

华为 AI Agent:企业内部管理的智能变革引擎(11/30)

一、华为 AI Agent 引领企业管理新潮流 在当今数字化飞速发展的时代&#xff0c;企业内部管理的高效性与智能化成为了决定企业竞争力的关键因素。华为&#xff0c;作为全球领先的科技巨头&#xff0c;其 AI Agent 技术在企业内部管理中的应用正掀起一场全新的变革浪潮。 AI Ag…

RustDesk内置ID服务器,Key教程

RustDesk内置ID服务器&#xff0c;Key教程 首先需要准备一个域名&#xff0c;并将其指定到你的 rustdesk 服务器 ip 地址上&#xff0c;这里编译采用的是Github Actions &#xff0c;说白了是就workflows&#xff0c;可以创建一些自动化的工作流程&#xff0c;例如代码的检查&a…

虚幻引擎结构之UObject

一. UObject 的介绍 UObject 是虚幻引擎中的核心基础类,所有其他游戏对象和资源类都直接或间接地继承自它。作为虚幻引擎的基石,UObject 提供了多项关键功能,包括内存管理、序列化、反射(introspection)、垃圾回收以及元数据支持。在虚幻引擎中,UObject 类的实例通常被称…

Python异常处理在“简易记事本”项目中的应用

Python异常处理在“简易记事本”项目中的应用 在“简易记事本”项目中&#xff0c;异常处理的使用尤为重要&#xff0c;因为文件操作过程中可能会遇到各种问题&#xff0c;例如文件不存在、权限不足或文件占用等。如果这些问题未被妥善处理&#xff0c;程序可能会崩溃&#xf…

Wend看源码-Java-集合学习(List)

摘要 本篇文章深入探讨了基于JDK 21版本的Java.util包中提供的多样化集合类型。在Java中集合共分类为三种数据结构&#xff1a;List、Set和Queue。本文将详细阐述这些数据类型的各自实现&#xff0c;并按照线程安全性进行分类&#xff0c;分别介绍非线程安全与线程安全的实现方…

阿里云新用户服务器配置

创建和链接实例 创建实例&#xff0c;点击左侧标签栏总的实例&#xff0c; 找到链接帮助 根据帮助中的ip信息&#xff0c;然后启用vscode的ssh链接 ctrlp选择配置&#xff0c;输入公网的ip即可 passwd修改root密码 安装conda 参考 https://blog.csdn.net/adreammaker/arti…

向量索引和文本嵌入有什么区别

向量索引和文本嵌入的区别 文本嵌入&#xff08;Text Embeddings&#xff09;&#xff1a;是将文本&#xff08;如一句话、段落、文章&#xff09;转换成 数字向量 的过程。每个文本都对应一个向量&#xff0c;向量的数值可以用来表达该文本的语义信息。常用的嵌入模型如 OpenA…

五金产品视觉检测

五金产品种类繁多&#xff0c;且与我们的日常生活紧密有关&#xff0c;依照加工工艺的不同&#xff0c;五金产品有压铸件&#xff0c;五金冲压件&#xff0c;铸件等&#xff0c;无论是哪种加工方式&#xff0c;产品总会存在各式各样的问题&#xff0c;今天我们就五金产品的缺陷…

Kotlin语言的软件工程

Kotlin语言的软件工程 引言 在现代软件开发中&#xff0c;选择合适的编程语言是项目成功的关键之一。随着移动互联网的迅猛发展&#xff0c;以及大数据和人工智能等新兴技术的崛起&#xff0c;Kotlin语言凭借其简洁、高效和安全等特性&#xff0c;迅速崛起为备受欢迎的编程语…

ip怎么查域名?IP和域名分别是什么?

为什么我们可以通过简单的域名访问网站&#xff0c;而不是记住一串复杂的数字&#xff1f;IP地址和域名之间到底是什么关系&#xff1f;在互联网的世界里&#xff0c;IP地址和域名是两种重要的概念&#xff0c;它们共同构成了我们日常上网的基础。 IP地址是互联网协议地址的缩…

拼多多纠偏,能否实现买卖平权?

科技新知 原创作者丨江蓠 编辑丨蕨影 当曾将仅退款、运费险作为标配的电商平台们开始听到商家诉求&#xff0c;有意优化营商环境&#xff0c;作为“仅退款”服务发起者的拼多多也坐不住了。 在推出一揽子减免计划讨好中小商家之后&#xff0c;拼多多近期被传正在内测精选用户…

XGPT用户帮助手册

文章目录 20242024.12.27 摘要 本文介绍如何使用XGPT软件, XGPT融合了当前最先进的人工智能技术&#xff0c;并专为国内用户优化。 2024 2024.12.27 XGPT v1正式发布, 特色功能: 具备图像文本多模态处理功能包含GPT等最先进模型国内可访问 B站视频介绍 图1 XGPT v1 快照

ubuntu停止.netcore正在运行程序的方法

在Ubuntu系统中停止正在运行的.NET Core程序&#xff0c;你可以使用以下几种方法&#xff1a; 使用kill命令&#xff1a; 如果你知道.NET Core程序的进程ID&#xff08;PID&#xff09;&#xff0c;你可以直接使用kill命令来停止它。首先&#xff0c;使用ps命令配合grep来查找.…

笔记:使用python对飞书用户活跃度统计的一个尝试

说明 一个python练习 代码 import json import time import openpyxl from openpyxl import load_workbook from datetime import datetime, timedelta import lark_oapi as lark from lark_oapi.api.admin.v1 import *def data_r(start_date, end_date):r_data []client la…

闲谭Scala(1)--简介

1. 背景 这是2024年的冬天&#xff0c;在此之前&#xff0c;我的技术栈已经多年不变。 前端使用JSVue&#xff0c;后端JavaSpringBoot&#xff0c;偶尔写一些小程序使用JSUniapp&#xff0c;偶尔写一些PC客户端使用C#WinForm。 看起来还行&#xff0c;其实Vue一直用的Vue2.x…