keycloak~对接login-status-iframe页面判断用户状态变更

news/发布时间2024/5/20 18:43:14

上次我们说了,keycloak的login-status-iframe页面的作用,并解决了跨域情况下,iframe与主页面数据传递的方法,这一次,我们主要分析login-status-iframe.html这个文件的源码,然后分析在我们系统中如何与这个页面对接。

login-status-iframe.html源码

<script>var init;function checkState(clientId, origin, sessionState, callback) {var cookie = getCookie();var checkCookie = function() {if (clientId === init.clientId && origin === init.origin) {var c = cookie.split('/');if (sessionState === c[2]) {callback('unchanged');} else {callback('changed');}} else {callback('error');}}if (!init) {var req = new XMLHttpRequest();var url = location.href.split("?")[0] + "/init";url += "?client_id=" + encodeURIComponent(clientId);url += "&origin=" + encodeURIComponent(origin);req.open('GET', url, true);req.onreadystatechange = function () {if (req.readyState === 4) {if (req.status === 204 || req.status === 1223) {init = {clientId: clientId,origin: origin}if (!cookie) {if (sessionState != '') {callback('changed');} else {callback('unchanged');}} else {checkCookie();}} else {callback('error');}}};req.send();} else  if (!cookie) {if (sessionState != '') {callback('changed');} else {callback('unchanged');}} else {checkCookie();}}function getCookie(){var cookie = getCookieByName('KEYCLOAK_SESSION');if (cookie === null) {return getCookieByName('KEYCLOAK_SESSION_LEGACY');}return cookie;}function getCookieByName(name){name = name + '=';var ca = document.cookie.split(';');for(var i=0; i<ca.length; i++){var c = ca[i].trim();if (c.indexOf(name)===0) return c.substring(name.length,c.length);}return null;}function receiveMessage(event){if (typeof event.data !== 'string') {return}var origin = event.origin;var data = event.data.split(' ');if (data.length != 2) {return;}var clientId = data[0];var sessionState = data[1];checkState(clientId, event.origin, sessionState, function(result) {event.source.postMessage(result, origin);});}window.addEventListener("message", receiveMessage, false);
</script>

具体方法说明

这个页面主要由以下4个方法组成,下面分别去介绍

  1. checkState(clientId, origin, sessionState, callback) 检查当前浏览器上,用户在keycloak登录的状态
  2. getCookie() 获取cookie中存储的用户状态
  3. getCookieByName(name) 获取指定key的cookie值
  4. receiveMessage(event) 接收从父页面通过postMessage传过来的消息

getCookieByName方法

按着指定向名称,从浏览器的cookie中获取,这是所有可见cookie的字符串,每对使用分号分开,咱们这个方法是返回了某个key对应的具体value.

getCookie方法

获取KEYCLOAK_SESSION的值,如果它不存在,就获取KEYCLOAK_SESSION_LEGACY的值,之所以有KEYCLOAK_SESSION_LEGACY,主要是考虑到了浏览器的兼容性问题。

receiveMessage方法

这个方法主要是用来接收主页面发过来的数据,然后进行状态检查的,子页面通过window.addEventListener("message", receiveMessage, false);来进行事件监听,主页面会提供client_id和sesssion_state,并使用空格将两个参数分开,然后在回调方法里,会向主页面进行通知,通过event.source.postMessage(result, origin);实现,result表示通知的内容,origin表示主页面的域名,其实这是为了安全考虑的,在主页面收到消息后,也会判断这个origin,会判断是否从子页面的域名;所以这个origin其实是事件的发起者的域名。

checkState方法

这是整个login-status-iframe.html页面的核心方法,主要用来判断登录状态,下面分步骤说一下:

  1. 它首先会从浏览器cookie中拿出KEYCLOAK_SESSION的值,它和主页面传过来的值做对比,如果相同状态就没改变(可能已登录或者未登录),如果不相同,如果说明状态改变了;
  2. 判断init是否初始化,如果没有,就从login-status-iframe.html/init?client_id=...这个keycloak的接口中,异步获取登录状态写入浏览器cookie,然后再用步骤1做状态判断;
  3. 如果init已经完成初始化,就直接检查cookie中的用户状态

主页面对接login-status-iframe.html页面

<iframe src="https://kc.com/auth/realms/{you}/protocol/openid-connect/login-status-iframe.html"id="keycloak-status-iframe" style="display:none"></iframe>
<script>function getQueryVariable(variable) {var query = window.location.search.substring(1);var vars = query.split("&");for (var i = 0; i < vars.length; i++) {var pair = vars[i].split("=");if (pair[0] == variable) {return pair[1];}}return (false);}var iframe = document.getElementById('keycloak-status-iframe');iframe.onload = function () {var val = "democlient ";if (getQueryVariable("code")!="" && getQueryVariable("code").split(".").length == 3) {val = "democlient " + getQueryVariable("code").split(".")[1];//这里向iframe传的参数是"client_id session_state"}iframe.contentWindow.postMessage(val, 'https://kc.com');window.addEventListener('message', function (event) {if (event.origin !== 'https://kc.com') {return;}if (event.data === 'unchanged') {alert('用户会话未发生变化');} else if (event.data === 'changed') {alert('用户会话状态发生变化,可能已经注销');}}, false);}
</script>

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

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

相关文章

既然来骗我了,那就站在技术角度给你分析一波这个诈骗信息。

你好呀,我是歪歪。 事情是这样的,前段时间有个人加我微信,说有个文案想要找我帮他们推广一下:链接点进去后,我一看标题是这样的:心里就有数了,知道这个相关的内容肯定是诈骗信息。 整个文案的内容大概是这样的:关键的点在于文案中他提供的二维码和 PC 端投递地址确实是…

从Redis读取.NET Core配置

在本文中,我们将创建一个自定义的.NET Core应用配置源和提供程序,用于从Redis中读取配置。在此之前,您需要稍微了解一些.NET Core配置提供程序的工作原理,相关的内容可以在Microsoft开发者官网搜索到。另外您可能还需要了解一些Redis的基础知识,比如Redis的基础数据类型,…

利用vb开发图片加密软件怎么样?

随着科技的发展,图片加密软件已经成为了我们生活中不可或缺的一部分。它不仅可以保护我们的隐私,还可以防止我们的图片被不法分子盗用。那么,如果我们利用VB(Visual Basic)来开发这样的软件会怎样呢?本文将从技术可行性、开发难度和应用前景三个方面进行探讨。利用VB开发图…

.net core中如何自定义静态文件目录、默认主页、和文件浏览目录?

在.NET Core中,UseStaticFiles、UseDefaultFiles、UseDirectoryBrowser和UseFileServer中间件用于处理静态文件和目录浏览。下面我将为你提供一个简单的例子,演示它们的用法。 首先,确保你的项目已经安装了Microsoft.AspNetCore.StaticFiles NuGet包,因为这是这些中间件的依…

汇编-div无符号整数除法

在32位模式下, DIV(无符号整数除法) 指令执行8位、16位及32位的无符号整数除法。无符号除法(unsigned division) 定义为一个无符号数除以另一个无符号数。其中, 除数为单个寄存器或内存操作数。格式如下: 【a=cb,读作c除以b(或b除c)。其中,c叫做被除数,b叫做除数】下表…

【算法】【线性表】有效的数独

1 题目 请你判断一个 9 x 9 的数独是否有效。只需要 根据以下规则 ,验证已经填入的数字是否有效即可。数字 1-9 在每一行只能出现一次。 数字 1-9 在每一列只能出现一次。 数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。(请参考示例图)注意:一个有效的数独(部分…