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


    上次我们说了,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页面

    
    
    
  • 相关阅读:
    理解交叉熵(Cross Entropy)
    【三维地图】开发攻略 —— 详解“GeoJSON”技术和应用场景
    MYSQL中LIKE(模糊查询)
    实验二:数据类型、运算符和表达式——桂林航天工业学院
    前端研习录(22)——JavaScript字符串及其方法合集
    [JS真好玩] 我帮掘金找到了一个小Bug,可利用该Bug增加专栏粉丝数
    2021美亚团队赛复盘
    kafka消费者模式
    react中受控组件与非受控组件
    咸鱼ESP32实例—MQTT 点亮LED
  • 原文地址:https://www.cnblogs.com/lori/p/17925956.html