一文理解登录鉴权(Cookie、Session、Jwt、CAS、SSO)

1 前言

登录鉴权是任何一个网站都无法绕开的部分,当系统要正式上线前都会要求接入统一登陆系统,一方面能够让网站只允许合法的用户访问,另一方面,当用户在网站上进行操作时也需要识别操作的用户,用作后期的操作审计。

2 Cookie & Session

由于HTTP是无状态的,也就是说,访问某个网站后,下一次再次访问,网站不能够识别出两次访问是否是同一个客户端。因此,为了能够对用户做验证,保障网站只能被合法的用户访问,需要将HTTP改成有状态的,此时就需要Cookie和Session配合使用。

需要识别当前HTTP请求是谁发起,就需要在后端存储用户信息,例如,用户ID、用户名、用户部门等,这些信息就存储在Session中,但是,在一段时间,可能有大量用户访问网站,也就是说,后端应该是存储一个字典,那么,哪一个用户才是当前这个请求的呢?这时就需要使用Cookie,Cookie是存储在客户端(浏览器)中的信息,将Session字典的键存储到客户端,当用户访问网站时,就会携带该Cookie,后端收到请求后,根据Cookie中的键就可以找到Session字典对应的值,也就能够识别当前用户的信息。

请添加图片描述

如上图所示,Cookie的存储形式也相当于KV,因此,最重要的属性就是名字和值。当前浏览器存储了SESSIONID=23456的Cookie,当用户通过该浏览器访问后端服务时,就会携带该Cookie(至于为什么会携带,这是Cookie本身的机制,当然还要看Cookie所属域名),后端服务收到请求后,读取其中的Cookie,然后查询Session,就可以知道当前访问的用户是Hanmeimei。

上述过程只涉及到用户已经登陆,并且通过Session和Cookie关联用户信息,另外一部分比较重要的就是用户登陆,例如,如果后端收到请求后,从后端Session中查询不到用户信息该怎么办呢?

3 SSO & Jwt & CAS

在登陆部分,经常听到或者看到的有三个单词:

  • SSO(Single Sign On):单点登录,当用户登录一个平台后,再去访问关联的其他平台,不需要重新登录,例如,如果登录了OA系统,再登录内部的gitlab、云平台等都可以直接访问。所以,SSO描述的更多的是一种现象,也就是说,符合上述的现象都可以称之为SSO。
  • JWT(Json Web Token):基于Token的WEB认证方式,与上面使用Session存储用户信息的方式不同,这种方式在登陆后会将用户信息经过加密成Token,前端收到后存储到Cookie或者LocalStorage,当下一次访问时,将Token放到请求头的Authorization。所以,JWT指的更多的是用户信息的存放方式,这种方式在发起后端API请求时也经常使用:先调用/api/login接口,返回Token,得到Token后,直接访问其他业务接口。
  • CAS(Central Authentication Service):统一身份认证服务,是SSO的一种实现,在实现过程中,也集成了JWT,将用户信息放到Token中。所以,严格意义上来说,CAS是一套用于实现SSO的系统,或者说,CAS是一个认证服务器,提供用户登陆验证的能力。

根据上面所说的,CAS是一套认证系统,它可以用于生成用户登陆的Token,而客户端可以以JWT的方式进行使用,例如拿到了之后存放到Cookie中。

4 gin中使用SSO

完整的CAS登陆流程在网上有很多,这里也不再赘述。下面就来说说,在gin中如何使用SSO接入公司的单点登录。

系统需要接入单点登录,就需要引入web的中间件:中间件是web框架提供的一种能力,可以在web的请求处理流程中加入业务自己的部分,例如,登陆验证、日志记录、时耗记录等。

具体流程如下:

  • 在中间件中判断用户是否登录,如果没有登录,则跳转到CAS的URL,CAS会判断用户是否登录,如果没有登录会跳转到登录页面
  • 当用户在CAS的登录页面输入用户名和密码登录后,会跳转到业务系统,并且会携带ticket,业务系统根据ticket去CAS验证,如果CAS验证通过,会返回用户信息给业务系统
  • 业务系统将用户信息保存到Session中,后续的请求就通过Session得到用户信息
// main.go 为gin添加中间件
r := gin.Default()
r.Use(Authenticate())// middleware.go
func Authenticate() gin.HandlerFunc {return func(c *gin.Context) {// 从session中获取用户信息session := sessions.Default(c)userName := session.Get("user_name")if userName == nil || userName == "" {// 用户在当前平台没有登录,则需要获取ticket// 这里的逻辑在不同的实现中可能会不一样,// 有的可以直接从query参数获取ticket,有的是直接放在cookie中ticket, _ := c.Cookie("SESSIONID")if ticket == "" {// 没有用户的cookie,说明没有通过登录验证,需要把session中的用户置空session.Set("user_name", "")session.Set("user_id", "")c.Next()return}// 通过ticket调用CAS接口获取用户信息,// 如果未获取到,说明用户确实没有登录,则跳转到CAS登录页面// 在跳转时需要带上当前的页面地址用于登录成功后的跳转user := handler.GetLoginUser(ticket)if user.UserId == "" {params := url.Values{}params.Add("service", fmt.Sprintf("http://%s", c.Request.URL.String())c.Redirect(http.StatusFound, fmt.Sprintf("%s?%s", config.Config.AuthLoginUrl, params.Encode()))return} else {// 获取到用户信息,则将用户信息写入sessionsession.Set("user_name", user.UserName)session.Set("user_id", user.UserId)session.Save()c.Next()}} else {c.Next()}}
}

5 前后端分离

现在的应用架构都采用前后端分离的方式,那么前后端分离的SSO跟非前后端分离有什么区别呢?

比较大的区别应该是在跳转部分的service参数:如果是前后端不分离,那么后端接收到的路由就是实际的页面地址,因此,如果登录成功跳转回来的话是可以直接用后端请求到的地址。如果前后端分离,跳转回来的页面肯定应该是前端的地址,这时候,跳转动作就只能在前端进行:

    // 获取用户信息async getUserName() {let token = getCookie("SESSIONID")if (token === "") {window.location.href = 'https://cas.example.com/cas/login?service=' + window.location.href} else {const out = await getUserProfile()this.username = out.Dataif (this.username === '') {window.location.href = 'https://cas.example.com/cas/login?service=' + window.location.href}}}

另外,在前后端分离的情况下,如果前端和后端不在同一个nginx下,会出现跨域问题。

6 跨域

跨域问题出现的原因是浏览器的同源访问限制策略,同源指的是相同的协议(例如,都是http)、域名、端口。为了安全起见,当浏览器发起XHR请求时,浏览器会查看当前源和请求的源是否相同,如果不相同就会禁止访问。

因此,跨域问题的出现有两个要素:

  • 不同源
  • XHR请求

如何解决跨域的问题呢?

常见的方案有三种:

  • 修改浏览器设置,禁用浏览器安全策略
  • JSONP,利用了非XHR请求不存在跨域,但是它只支持HTTP的GET请求
  • CORS,在响应头增加Access-Control-Allow-Origin选项,说明服务端允许访问的域名
  • 修改nginx或者apache的配置,当然也是在响应头增加Access-Control-Allow-Origin选项

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

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

相关文章

社区团购:优势、模式与未来发展趋势

随着互联网的普及和电子商务的快速发展,社区团购作为一种新兴的商业模式,正逐渐在各大城市流行起来。本文将详细阐述社区团购的基本概念、优势、模式以及未来发展趋势。 一、社区团购的基本概念和现状 社区团购是一种基于社区网络的电子商务模式&#…

docker jenkins

mkdir jenkins_home chown -R 1000:1000 /root/jenkins_home/docker run -d --name myjenkins -v /root/jenkins_home:/var/jenkins_home -p 8080:8080 -p 50000:50000 --restarton-failure jenkins/jenkins:lts-jdk17参考 Official Jenkins Docker imageDocker 搭建 Jenkins …

灾害与环境遥感团队本科生在IEEE TGRS 发表高水平论文

2023年9月27日,地球科学和遥感领域顶级期刊《IEEE Transactions on Geoscience and Remote Sensing》(IEEE TGRS)在线预刊发了灾害与环境遥感团队的最新研究成果“A novel spectral index for rapid dust-proof net mapping based on Sentine…

想做WMS仓库管理系统,找了好久才找到云表

公司内部仓库管理原方式均基于人工电子表格管理方式来实现收发存管理,没有流程化管理,无法保证数据的准确性和及时性,同时现场操作和数据核对会出现不同步的情况,无法提高仓库的运作效率,因此,我们基于云表…

【设计模式】单例模式、“多例模式”的实现以及对单例的一些思考

文章目录 1.概述2.单例模式实现代码2.1.饿汉式单例2.2.懒汉式单例2.3.双检锁单例2.4.静态内部类单例2.5.枚举单例 3.对单例的一些思考3.1.是否需要严格的禁止单例被破坏?3.2.懒汉式真的比饿汉式更佳吗?3.3.单例存在的问题 4.其他作用范围的单例模式4.1.线…

关闭VS Code中的鼠标悬停时的提示框(MDN Reference)

在使用VS Code编辑器写html文件时,鼠标悬停在写的某些内容时会弹出一个提示框,如下图: 这个提示是比较烦人的,接下来分享关闭它的教程: 这里是以Win10版的Visual Studio Code为例 1.打开VS Code 的设置界面 2.在扩展…

js构造函数

构造函数 通过 new 函数名 来实例化对象的函数叫构造函数。 任何的函数都可以作为构造函数存在。之所以有构造函数与普通函数之分,主要从功能上进行区别的,构造函数的主要 功能为 初始化对象,特点是和new 一起使用。new就是在创建对象&#x…

《开箱元宇宙》:《福布斯》如何通过 Web3 改进讲故事的方式

你们是否想知道 The Sandbox 如何融入世界上最具标志性的品牌和名人的战略?在本期《开箱元宇宙》系列中,我们与《福布斯》一起探讨了他们为何决定在 The Sandbox 中尝试 Web3,以及他们如何改变讲故事的方式,以便在一次体验中吸引超…

字节跳动2023测试开发岗 3+1 面经+经验分享(收到offer,入职月薪27K)

现在,招聘黄金时间已经来临,在网上看了很多大佬的面经,也加了很多交流群,受到了很多朋友的提点,今天终于轮到我来分享面经啦,之前面试了几家公司,最后在十月初拿到了字节跳动测试岗的 offer&…

口袋参谋:如何写出高权重标题?用对这招很重要!

​如何写出高权重标题?这是99.99%的卖家都存在的疑虑! 以前写高权重标题,很多卖家往往会复制同行竞品爆款标题到淘宝首页搜索框,然后在全标题后面加上几个字母,就可以拆分爆款标题。 这个问题我之前也说过&#xff0…

【GO入门】环境配置及Vscode配置

1 GO环境配置 欢迎来到Go的世界,让我们开始探索吧! Go是一种新的语言,一种并发的、带垃圾回收的、快速编译的语言。它具有以下特点: 它可以在一台计算机上用几秒钟的时间编译一个大型的Go程序。Go为软件构造提供了一种模型&…

【C++】:string用法详解

朋友们、伙计们,我们又见面了,本期来给大家解读一下有关Linux的基础知识点,如果看完之后对你有一定的启发,那么请留下你的三连,祝大家心想事成! C 语 言 专 栏:C语言:从入门到精通 数…

使用PyTorch解决多分类问题:构建、训练和评估深度学习模型

💗💗💗欢迎来到我的博客,你将找到有关如何使用技术解决问题的文章,也会找到某个技术的学习路线。无论你是何种职业,我都希望我的博客对你有所帮助。最后不要忘记订阅我的博客以获取最新文章,也欢…

编译linux内核模块时的make -C M= modules的参数说明

在linux下编译可加载内核模块形成.ko文件的makefile中的核心语句是: $(MAKE) -C $(KERNEL_DIR) M(PWD) modules 这句是Makefile的规则:这里的 $(MAKE)就相当于make;-C 选项的作用是指将当前工作目录转移到你所指定的位置,一般都是内核源代…

Vue配置全局变量config.js

Vue配置全局变量config.js 若config.js在public目录下 在index.html中引入 这样配置是为了防止路由前缀&#xff0c;如果直接“/config.js”&#xff0c;若路由没有前缀还好&#xff0c;要是有就需要配置为“<% BASE_URL %>config.js”

【01】基础知识:React简介与案例

一、React 简介 React 概述 React 是一个将数据渲染为 HTML 视图 的开源 JavaScript 库 React 由 FaceBook 开发&#xff0c;且开源 为什么要学习 React 1、原生 JavaScript 操作 DOM 繁琐、效率低&#xff08;使用 DOM-API 操作 UI&#xff09; 2、使用 JavaScript 直接…

Xilinx IP 10G Ethernet PCS/PMA IP Core

Vivado 10G Ethernet PCS/PMA介绍 1介绍 完整的10G以太网接口如下图,分为10G PHY和10G MAC两部分。 这篇文章重点讲 10G Ethernet PCS/PMA。 2 IP的基本介绍 10G以太网物理编码子层/物理介质连接(PCS/PMA)核心在Xilinx 10G以太网介质访问控制器(MAC)核心和具有10Gb/s…

Linux网络编程系列之UDP组播

Linux网络编程系列 &#xff08;够吃&#xff0c;管饱&#xff09; 1、Linux网络编程系列之网络编程基础 2、Linux网络编程系列之TCP协议编程 3、Linux网络编程系列之UDP协议编程 4、Linux网络编程系列之UDP广播 5、Linux网络编程系列之UDP组播 6、Linux网络编程系列之服务器编…

尚硅谷Flink(一)

目录 ☄️前置工作 fenfa脚本 &#x1f30b;概述 ☄️Flink是什么 ☄️特点&#xff08;多nb&#xff09; ☄️应用场景&#xff08;不用看&#xff09; ☄️分层API &#x1f30b;配环境 ☄️wordcount ☄️WcDemoUnboundStreaming &#x1f30b;集群部署 ☄️集…

xml的语法

<!-- 1、每一个xml,有且只有一个根标签&#xff0c;所有xml标签必须写在根标签中 2、标签必须要有合闭 3、xml格式是否正确&#xff0c;可以通过浏览器打开xml。来校验xml格式是否正确 4、xml是区别大小写的 5、xml书写标签名时&#xff0c;不要出现空格等特…