前端跨域登录演示

{{ time }}

是把token分别保存至不同域名的localStorage

主站登录页 http://www.main.com/login.html:

<!DOCTYPE html>
<html lang="zh-cn">

<head>
    <meta charset="utf-8">
    <title>跨域登录演示</title>
    <link rel="stylesheet" href="//static.class4ever.com/layui/v2.5.5/css/layui.css">
    <style>
        [v-cloak] {
            display: none;
        }
    </style>
</head>

<body>
    <div id="app" v-cloak>
        <table class="layui-table" style="width:400px;margin:100px auto;">
            <tr>
                <td colspan="2">
                    <h2>
                        跨域登录演示
                    </h2>
                </td>
            </tr>
            <tr>
                <td>用户名</td>
                <td>{{ username }}</td>
            </tr>
            <tr>
                <td>token</td>
                <td>
                    <input v-model="token" class="layui-input" type="text">
                </td>
            </tr>
            <tr>
                <td>登录结果</td>
                <td id="log" style="color:blue;"></td>
            </tr>
            <tr>
                <td colspan="2">
                    <button @click="login" class="layui-btn layui-btn-normal">登录</button>
                </td>
            </tr>
        </table>

        <iframe v-for="(domain,k) in cross_domain_list" :name="'_cross_domain_' + k"
            :src="domain + '/cross_domain.html'" style="display: none;"></iframe>
    </div>
</body>
<script src="//static.class4ever.com/jquery/jquery-3.4.1.min.js"></script>
<script src="//static.class4ever.com/vuejs/v2.6.12/vue.min.js"></script>

<script>
    const app = new Vue({
        el: '#app',
        data: {
            /* 
               跨域的域名列表:
                  1. 不包含本页所在的域名
                  2. 协议名要正确
                  3. 须在该域名下配置/cross_domain.html
            */
            cross_domain_list: [
                'http://www.a.com',
                'http://www.b.com'
            ],

            username: '小明',
            token: '测试token',

            //登录过程
            login_success: 0,
        },
        mounted: function () {
            /* 监听收到的消息 */
            window.addEventListener('message', function (e) {
                let res = e.data;
                if (res.code === 200) {
                    let key = res.data.domain_key
                    let domain = app.cross_domain_list[key]

                    app.log(domain + ' 已登录<br>')

                    if (++app.login_success === app.cross_domain_list.length)
                        app.log('所有域名都已登录')
                }
            }, false);
        },
        methods: {
            /* 登录初始化 */
            login_init: function () {
                this.login_success = 0

                $('#log').empty()
            },


            /* 记录日志 */
            log: function (str) {
                $('#log').append(str)
            },


            /* 本域名登录 */
            self_login: function () {
                localStorage.setItem('username', this.username);
                localStorage.setItem('token', this.token);

                let protocol = window.location.protocol
                let domain = window.location.host

                $('#log').append(protocol + '://' + domain + ' 已登录<br>')
            },


            /* 跨域登录 */
            cross_login: function () {
                var domain_list = this.cross_domain_list
                for (let key in domain_list) {
                    let data = {
                        domain_key: key,
                        username: this.username,
                        token: this.token
                    }

                    let name = '_cross_domain_' + key

                    window.frames[name].postMessage(data, domain_list[key]);
                }
            },


            /* 
              测试登录: 
                向其他所有域名发送token
            */
            login: function () {
                this.login_init()

                this.self_login()

                this.cross_login()
            }
        }
    })
</script>

</html>

再给除主站外, 要跨站登录的域名分别配置/cross_domain.html:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="utf-8">
</head>

<body></body>
<script>
    window.addEventListener('message', function (e) {
        if (e.source != window.parent)
            return;

        //保存用户名和token        
        localStorage.setItem('username', e.data.username);
        localStorage.setItem('token', e.data.token);

        let res = {
            code: 200,
            message: 'success',
            data: {
                domain_key: e.data.domain_key
            }
        }

        window.parent.postMessage(res, '*');
    }, false);
</script>

</html>