历史版本3 :前台单点登录之AES加密示例 返回文档
编辑时间: 内容长度:图片数:目录数: 修改原因:

目录:

1. 概述编辑

1.1 版本

报表服务器版本插件版本
10.0V1.0

1.2 问题描述

前台单点登录 时,用户在自定义登录页面内输入的用户信息需要发送到数据决策系统中进行登录验证。

在发送过程中,以明文形式传输的用户密码易受到劫持攻击。如何保障用户密码传输的安全性呢?

1.3 实现思路

FineReport 支持使用 AES 对称加密方式对用户输入的密码进行加密,将加密后的密文发送至数据决策系统。

系统会在后台进行解密,当解密后的密码与数据决策系统内用户密码一致时,用户即可成功登录数据决策系统。

1.3.1 AES对称加密逻辑

用户在自定义登录页面内输入的明文密码会经过以下步骤从前台传输至后台,最终用于登录验证。如下图所示:


发送方:

  • 用户在网页中输入密码,即明文 P

  • 使用工程特有的密钥 K 对明文密码 P 进行 AES 加密,得到密文 C

  • 调用 前台单点登录接口 传输密文 C,并加上 encrypted 参数说明密码是经过 AES 加密后的密文

接收方:

密文 C 经过网络传输到达接收方,系统会用自带的 AES 解密函数和秘钥 K 去解密密码。

1.3.2 实现步骤

1)获取 AES 秘钥。本文提供以下两种方式:

注1:推荐方案一,通过插件能够实时的获取秘钥,不用担心秘钥改变的情况。

注2:工程初始化秘钥为 16 位字符串,保存在 FineDB 数据库的 SecurityConfig.frontSeed 字段中,用户可以使用初始化密钥或者自定义修改密钥。详情请参见:fine_conf_entity可视化配置

方法一:安装 frontseed 插件后,通过/url/frontseed请求返回值中的 frontSeed 字段获取密钥。

方法二:直接在 FineDB 数据库中查询 FINE_CONF_ENTIT 表的 SecurityConfig.frontSeed 字段,得到的值即为工程初始化密钥。

2)使用 fineui 中的 BI.aesEncrypt(password, frontSeed) 对明文密码进行 AES 对称加密。

3)设置是否使用加密的参数 encrypted 为 true,告知后台该密码是经 AES 加密后的密文,需进行解密。

4)密文传输到后台进行解密。

2. 获取密钥编辑

获取 AES 密钥,用于加密用户输入的登录密码。

2.1 方法一:通过插件获取密钥

注1:使用插件获取密钥的方法需要关闭 安全防护 中的「内容嗅探攻击防护」功能。

注2:请勿解压下载得到的压缩包,直接安装即可。

点击下载插件并手动安装:fr-plugin-frontseed-1.0.zip

设计器插件安装方法参照:设计器插件管理

服务器安装插件方法参照:服务器插件管理

2.2 方法二:通过数据库查询获取密钥

1)连接内置数据库 FineDB,详情请参见:FineDB 数据库简介 中 2.3 节设计器连接 FineDB。

2)新建数据库查询,选择数据连接为 FineDB。

输入 SQL 语句:select value from FINE_CONF_ENTITY where id = 'SecurityConfig.frontSeed',点击「预览」,得到的「value」值即为工程初始化密钥。如下图所示:

3. 新建登录页面编辑

新建 HTML 文件自定义决策平台登录页面,命名为Aeslogin.html。代码如下所示:

注1:若选择方法二「通过数据库查询获取密钥」,需要将本文提供的代码进行以下修改:

     将 encodeURIComponent(BI.aesEncrypt(password, res1.frontSeed)) 中的 res1.frontSeed 参数更改为 2.2 节获取的密钥。

    示例:若密钥为"1b1cd997b655aa33",则更改为 encodeURIComponent(BI.aesEncrypt(password, "1b1cd997b655aa33"))

注2:根据实际情况修改代码中的访问路径或端口号。

点击下载并解压获得 HTML 文件:Aeslogin.zip

<html><head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>跨域登录加密Demo</title>
    <!-- 自定义样式,根据实际需求使用 -->
    <link href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
    <!-- aes加密需要使用到对应的方法,因此需要引用工程中的fineui。如果自行实现aes加密可以不引用 -->
    <script src="http://localhost:8075/webroot/decision/file?path=/com/fr/web/ui/fineui.min.js&type=plain&parser=plain"></script>
    <style>
        .container {
            display: flex;
            justify-content: center;
        }
        .login-box {
            width: 300px;
            margin-top: 100px;
        }
        .login-box h2 {
            font-size: 26px;
            text-align: center;
            margin-bottom: 25px;
        }
        .login-item {
            margin-bottom: 20px;
        }
    </style>
<body>
<div class="container">
    <form class="login-box" action="" method="post" onsubmit="return false;">
        <h2>数据决策系统</h2>
        <div class="login-item">
            <label for="inputUsername" class="sr-only">用户名</label>
            <input type="text" id="inputUsername" class="form-control" placeholder="用户名" required="" autofocus="">
        </div>
        <div class="login-item">
            <label for="inputPassword" class="sr-only">密码</label>
            <!--  autocomplete="off"属性,阻止浏览器从cookies获取数据填充登录表单 -->
            <input type="text" id="inputPassword" οnfοcus="this.type='password'" class="form-control" placeholder="密码" required="" autocomplete="off">
        </div>
        <button class="btn btn-lg btn-primary btn-block" type="submit" id="submitBtn">登录</button>
    </form>
</div>
<script>
    document.getElementById("submitBtn").addEventListener("click", function () {
        doSubmit();
    });
    function doSubmit() {
        var username = document.getElementById("inputUsername").value.trim();   //获取输入的用户名
        var password = document.getElementById("inputPassword").value.trim();   //获取输入的密码
        if (username === "") {
            window.alert("请输入用户名");
            return false;
        }
        if (password === "") {
            window.alert("请输入密码");
            return false;
        }
        $.ajax({
            url: "http://localhost:8075/webroot/decision/url/frontseed",    //获取AES密钥
            dataType:"jsonp",
            jsonp:"callback",
            success: function (res1) {
                var url = "http://localhost:8075/webroot/decision/login/cross/domain"
                    + "?fine_username=" + encodeURIComponent(username) + "&fine_password=" + encodeURIComponent(BI.aesEncrypt(password, res1.frontSeed))
                    + "&encrypted=true&validity=-1";    //调用前台单点登录接口
                $.ajax({
                    url: url,//单点登录的管理平台报表服务器
                    // timeout: 5000,//超时时间(单位:毫秒)
                    dataType:"jsonp",//跨域采用jsonp方式
                    jsonp:"callback",
                    success: function (res) {
                        if (res.url) {
                            window.location = res.url;  //跳转到数据决策系统
                        } else {
                            alert(res.errorMsg);
                        }
                    },
                    error: function () {
                        console.log(arguments)
                        // alert("超时或服务器其他错误");// 登录失败(超时或服务器其他错误)
                    }
                });
            },
            error: function () {
                console.log(arguments)
            }
        });
    }
</script>
</body>
</html>

4. 将 HTML 文件放到指定位置编辑

将 HTML 文件保存至%FR_HOME%/webapps/webroot文件夹下,如下图所示:

5. 效果查看编辑

在浏览器中访问http://localhost:8075/webroot/AESlogin.html,输入数据决策系统内用户的账号和密码。

本示例选择用户 Anna(Anna,123456),输入登录信息后点击「登录」按钮,即可成功访问数据决策系统。如下图所示:


在本示例中,用户输入密码为「123456」,示例工程的初始化密钥为「1b1cd997b655aa33」,则 AES 加密后的密文为「MrIg7ZKP5cEIliWaWseZiA==」,再使用encodeURIComponent()对特殊字符转码为「MrIg7ZKP5cEIliWaWseZiA%3D%3D」。

用户点击「登录」按钮,最终调用接口如下: