1. 概述
1.1 版本
報表伺服器版本 |
---|
11.0 |
1.2 問題描述
使用者在使用自訂登入網頁時,需要將輸入明文密碼傳送到數據決策系統中進行登入驗證。在傳輸程式中,明文密碼的安全性較低,使用者希望能夠對密碼進行加密,以密文形式傳輸來保障資訊的安全性。
1.3 實現思路
使用加密算法對使用者在登入頁輸入密碼進行加密,將加密後的密文傳輸至數據決策系統進行登入驗證。
資料庫中儲存加密後的密文,並透過 同步使用者 的方式將資料庫中的資訊儲存至數據決策系統。當傳輸的密文與數據決策系統中所儲存的密文一致時,登入驗證透過,使用者成功登入數據決策系統。如下圖所示:
實現步驟:
1)準備加密 JS 檔案,用於加密使用者在登入頁面輸入明文密碼。
2)建立 HTML 檔案,自訂登入網頁面。實現以下效果:
引用步驟 1 準備的加密 JS 檔案,呼叫加密方法將使用者輸入明文轉化成密文。
呼叫單點登入API,將密文傳輸至數據決策系統進行登入驗證。
登入驗證成功後跳轉到使用者的數據決策系統頁面。
3)將 HTML 檔案與加密 JS 檔案放到指定位置。
4)建立伺服器資料集,儲存使用者的登入資訊,包括帳號、登入密碼等,其中登入密碼為加密後的密文。
注:同步使用者後,系統會對伺服器資料集中該密文進行一次 SHA256 加密,得到的密文寫入 FineDB 庫。
5)同步使用者資訊至數據決策系統,用於登入驗證。
2. 範例
本文範例:自訂一個數據決策系統登入頁,對使用者輸入密碼進行 md5(16位大寫)加密,使用加密後的密文進行登入驗證,驗證透過後跳轉到使用者的數據決策系統頁面。
2.1 準備加密 JS 檔案
準備加密 JS 檔案,用於加密使用者在登入頁面輸入明文密碼。
建立 JS 檔案,命名為 md5.js,程式碼如下所示:
點選下載並解壓獲得加密 JS 檔案:加密.zip
注:本節還提供了 sha256.js 加密檔案,使用者可按需選用,使用步驟參考第二節範例即可。
var hexcase = 1;
var b64pad = "";
var chrsz = 8;
var mode = 16; //模式選擇 (16為16位的加密 32 為32位的加密)
function preprocess(form)
{
var str = "";
str += form.verifycode.value;
str = str.toUpperCase();
form.p.value = md5(md5_3(form.p.value)+str);
return true;
}
function md5_3(s)
{
var tmp = new Array;
tmp = core_md5(str2binl(s), s.length * chrsz);
tmp = core_md5(tmp, 16 * chrsz);
tmp = core_md5(tmp, 16 * chrsz);
return binl2hex(tmp);
}
function md5(s)
{
return hex_md5(s);
}
function hex_md5(s)
{
return binl2hex(core_md5(str2binl(s), s.length * chrsz));
}
function b64_md5(s)
{
return binl2b64(core_md5(str2binl(s), s.length * chrsz));
}
function str_md5(s)
{
return binl2str(core_md5(str2binl(s), s.length * chrsz));
}
function hex_hmac_md5(key, data)
{
return binl2hex(core_hmac_md5(key, data));
}
function b64_hmac_md5(key, data)
{
return binl2b64(core_hmac_md5(key, data));
}
function str_hmac_md5(key, data)
{
return binl2str(core_hmac_md5(key, data));
}
function md5_vm_test()
{
return hex_md5("abc") == "900150983cd24fb0d6963f7d28e17f72";
}
function core_md5(x, len)
{
x[len >> 5] |= 0x80 << ((len) % 32);
x[(((len + 64) >>> 9) << 4) + 14] = len;
var a = 1732584193;
var b = - 271733879;
var c = - 1732584194;
var d = 271733878;
for (var i = 0; i < x.length; i += 16)
{
var olda = a;
var oldb = b;
var oldc = c;
var oldd = d;
a = md5_ff(a, b, c, d, x[i + 0], 7, - 680876936);
d = md5_ff(d, a, b, c, x[i + 1], 12, - 389564586);
c = md5_ff(c, d, a, b, x[i + 2], 17, 606105819);
b = md5_ff(b, c, d, a, x[i + 3], 22, - 1044525330);
a = md5_ff(a, b, c, d, x[i + 4], 7, - 176418897);
d = md5_ff(d, a, b, c, x[i + 5], 12, 1200080426);
c = md5_ff(c, d, a, b, x[i + 6], 17, - 1473231341);
b = md5_ff(b, c, d, a, x[i + 7], 22, - 45705983);
a = md5_ff(a, b, c, d, x[i + 8], 7, 1770035416);
d = md5_ff(d, a, b, c, x[i + 9], 12, - 1958414417);
c = md5_ff(c, d, a, b, x[i + 10], 17, - 42063);
b = md5_ff(b, c, d, a, x[i + 11], 22, - 1990404162);
a = md5_ff(a, b, c, d, x[i + 12], 7, 1804603682);
d = md5_ff(d, a, b, c, x[i + 13], 12, - 40341101);
c = md5_ff(c, d, a, b, x[i + 14], 17, - 1502002290);
b = md5_ff(b, c, d, a, x[i + 15], 22, 1236535329);
a = md5_gg(a, b, c, d, x[i + 1], 5, - 165796510);
d = md5_gg(d, a, b, c, x[i + 6], 9, - 1069501632);
c = md5_gg(c, d, a, b, x[i + 11], 14, 643717713);
b = md5_gg(b, c, d, a, x[i + 0], 20, - 373897302);
a = md5_gg(a, b, c, d, x[i + 5], 5, - 701558691);
d = md5_gg(d, a, b, c, x[i + 10], 9, 38016083);
c = md5_gg(c, d, a, b, x[i + 15], 14, - 660478335);
b = md5_gg(b, c, d, a, x[i + 4], 20, - 405537848);
a = md5_gg(a, b, c, d, x[i + 9], 5, 568446438);
d = md5_gg(d, a, b, c, x[i + 14], 9, - 1019803690);
c = md5_gg(c, d, a, b, x[i + 3], 14, - 187363961);
b = md5_gg(b, c, d, a, x[i + 8], 20, 1163531501);
a = md5_gg(a, b, c, d, x[i + 13], 5, - 1444681467);
d = md5_gg(d, a, b, c, x[i + 2], 9, - 51403784);
c = md5_gg(c, d, a, b, x[i + 7], 14, 1735328473);
b = md5_gg(b, c, d, a, x[i + 12], 20, - 1926607734);
a = md5_hh(a, b, c, d, x[i + 5], 4, - 378558);
d = md5_hh(d, a, b, c, x[i + 8], 11, - 2022574463);
c = md5_hh(c, d, a, b, x[i + 11], 16, 1839030562);
b = md5_hh(b, c, d, a, x[i + 14], 23, - 35309556);
a = md5_hh(a, b, c, d, x[i + 1], 4, - 1530992060);
d = md5_hh(d, a, b, c, x[i + 4], 11, 1272893353);
c = md5_hh(c, d, a, b, x[i + 7], 16, - 155497632);
b = md5_hh(b, c, d, a, x[i + 10], 23, - 1094730640);
a = md5_hh(a, b, c, d, x[i + 13], 4, 681279174);
d = md5_hh(d, a, b, c, x[i + 0], 11, - 358537222);
c = md5_hh(c, d, a, b, x[i + 3], 16, - 722521979);
b = md5_hh(b, c, d, a, x[i + 6], 23, 76029189);
a = md5_hh(a, b, c, d, x[i + 9], 4, - 640364487);
d = md5_hh(d, a, b, c, x[i + 12], 11, - 421815835);
c = md5_hh(c, d, a, b, x[i + 15], 16, 530742520);
b = md5_hh(b, c, d, a, x[i + 2], 23, - 995338651);
a = md5_ii(a, b, c, d, x[i + 0], 6, - 198630844);
d = md5_ii(d, a, b, c, x[i + 7], 10, 1126891415);
c = md5_ii(c, d, a, b, x[i + 14], 15, - 1416354905);
b = md5_ii(b, c, d, a, x[i + 5], 21, - 57434055);
a = md5_ii(a, b, c, d, x[i + 12], 6, 1700485571);
d = md5_ii(d, a, b, c, x[i + 3], 10, - 1894986606);
c = md5_ii(c, d, a, b, x[i + 10], 15, - 1051523);
b = md5_ii(b, c, d, a, x[i + 1], 21, - 2054922799);
a = md5_ii(a, b, c, d, x[i + 8], 6, 1873313359);
d = md5_ii(d, a, b, c, x[i + 15], 10, - 30611744);
c = md5_ii(c, d, a, b, x[i + 6], 15, - 1560198380);
b = md5_ii(b, c, d, a, x[i + 13], 21, 1309151649);
a = md5_ii(a, b, c, d, x[i + 4], 6, - 145523070);
d = md5_ii(d, a, b, c, x[i + 11], 10, - 1120210379);
c = md5_ii(c, d, a, b, x[i + 2], 15, 718787259);
b = md5_ii(b, c, d, a, x[i + 9], 21, - 343485551);
a = safe_add(a, olda);
b = safe_add(b, oldb);
c = safe_add(c, oldc);
d = safe_add(d, oldd);
}
if (mode == 16)
{
return Array(b, c);
}
else
{
return Array(a, b, c, d);
}
}
function md5_cmn(q, a, b, x, s, t)
{
return safe_add(bit_rol(safe_add(safe_add(a, q), safe_add(x, t)), s), b);
}
function md5_ff(a, b, c, d, x, s, t)
{
return md5_cmn((b & c) | ((~b) & d), a, b, x, s, t);
}
function md5_gg(a, b, c, d, x, s, t)
{
return md5_cmn((b & d) | (c & (~d)), a, b, x, s, t);
}
function md5_hh(a, b, c, d, x, s, t)
{
return md5_cmn(b ^ c ^ d, a, b, x, s, t);
}
function md5_ii(a, b, c, d, x, s, t)
{
return md5_cmn(c ^ (b | (~d)), a, b, x, s, t);
}
function core_hmac_md5(key, data)
{
var bkey = str2binl(key);
if (bkey.length > 16)
bkey = core_md5(bkey, key.length * chrsz);
var ipad = Array(16), opad = Array(16);
for (var i = 0; i < 16; i++)
{
ipad[i] = bkey[i] ^ 0x36363636;
opad[i] = bkey[i] ^ 0x5C5C5C5C;
}
var hash = core_md5(ipad.concat(str2binl(data)), 512+data.length * chrsz);
return core_md5(opad.concat(hash), 512+128);
}
function safe_add(x, y)
{
var lsw = (x & 0xFFFF) + (y & 0xFFFF);
var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
return (msw << 16) | (lsw & 0xFFFF);
}
function bit_rol(num, cnt)
{
return (num << cnt) | (num >>> (32-cnt));
}
function str2binl(str)
{
var bin = Array();
var mask = (1 << chrsz) - 1;
for (var i = 0; i < str.length * chrsz; i += chrsz)
bin[i >> 5] |= (str.charCodeAt(i / chrsz) & mask) << (i % 32);
return bin;
}
function binl2str(bin)
{
var str = "";
var mask = (1 << chrsz) - 1;
for (var i = 0; i < bin.length * 32; i += chrsz)
str += String.fromCharCode((bin[i >> 5] >>> (i % 32)) & mask);
return str;
}
function binl2hex(binarray)
{
var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef";
var str = "";
for (var i = 0; i < binarray.length * 4; i++)
{
str += hex_tab.charAt((binarray[i >> 2] >> ((i % 4) * 8+4)) & 0xF) +
hex_tab.charAt((binarray[i >> 2] >> ((i % 4) * 8)) & 0xF);
}
return str;
}
function binl2b64(binarray)
{
var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
var str = "";
for (var i = 0; i < binarray.length * 4; i += 3)
{
var triplet = (((binarray[i >> 2] >> 8 * (i % 4)) & 0xFF) << 16) | ((
(binarray[i + 1 >> 2] >> 8 * ((i + 1) % 4)) & 0xFF) << 8) | ((binarray[i
+ 2 >> 2] >> 8 * ((i + 2) % 4)) & 0xFF);
for (var j = 0; j < 4; j++)
{
if (i * 8+j * 6 > binarray.length * 32)
str += b64pad;
else
str += tab.charAt((triplet >> 6 * (3-j)) & 0x3F);
}
}
return str;
}
在 2.2 節自訂登入網頁 login.html中引入 md5.js檔案後,可以在 doSubmit() 函式中直接呼叫 md5 加密方法對使用者輸入明文密碼進行加密。
使用方法如下:
注:md5.js 中提供了 6 種加密方法,包括:hex_md5(value)、b64_md5(value)、str_md5(value)、hex_hmac_md5(key, data)、b64_hmac_md5(key, data)、str_hmac_md5(key, data),使用者可按需選用。
<script type="text/javascript" src="./md5.js"></script> //引入 md5.js
var password = md5(document.getElementById("password").value.trim()); // 使用 md5 加密方法對使用者輸入密碼進行加密
2.2 建立登入頁面
建立 HTML 檔案自訂決策平台登入頁面,命名為login.html。完整程式碼如下所示:
注:需根據實際情況修改程式碼中的存取路徑或埠號。
點選下載並解壓獲得 HTML 檔案:login.zip
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>自訂登入網頁加密Demo</title>
<!-- 自訂樣式,根據實際需求使用 -->
<link href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
<script src="https://cdn.bootcss.com/html5shiv/3.7.3/html5shiv.min.js"></script>
<script src="https://cdn.bootcss.com/respond.js/1.4.2/respond.min.js"></script>
<script type="text/javascript" src="https://cdn.bootcss.com/jquery/1.9.1/jquery.min.js"></script>
<script type="text/javascript" src="./md5.js"></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 = md5(document.getElementById("inputPassword").value.trim()); //對使用者輸入密碼進行加密
if (username === "") {
window.alert("請輸入帳號");
return false;
}
if (password === "") {
window.alert("請輸入密碼");
return false;
}
var url = "http://localhost:8075/webroot/decision/login/cross/domain" + "?fine_username=" + username + "&fine_password=" + password + "&validity=" + -1;
jQuery.ajax({
url: url,//單點登入的管理平台報表伺服器
timeout: 5000,//逾時時間(單位:毫秒)
dataType:"jsonp",//跨域採用jsonp方式
jsonp:"callback",
success: function (res) {
console.log(res);
if (res.errorCode) {
window.alert(res.errorMsg);
}else {
// 儲存token並跳轉到對應連結
window.location.href = "http://localhost:8075/webroot/decision";
}
},
error: function () {
alert("逾時或伺服器其他錯誤");// 登入失敗(逾時或伺服器其他錯誤)
}
});
}
</script>
</body>
</html>
2.3 將檔案放到指定位置
將 login.html 和 md5.js 檔案儲存至%FR_HOME%/webapps/webroot檔案夾下,如下圖所示:
2.4 同步資料庫資訊至數據決策系統
2.4.1 資料準備
準備一張使用者資訊表,其中 password 資料列中的密碼為 md5( 16位大寫)加密後的密文。表結構如下圖所示:
範例:若使用者 a 在登入頁面實際輸入明文密碼為:123456,則 password 列中存放的密碼為 md5(16位大寫)加密後的密文:49BA59ABBE56E057。
點選下載使用者資訊表:同步使用者.xlsx
2.4.2 新增伺服器資料集
請自行使用第三方資料庫管理工具,將上表匯入資料庫,並建立系統與該資料庫的 資料連結 。下文將以 FRDemoTW 資料庫為例。
1)管理者登入數據決策系統,點選「管理系統>資料連結>伺服器資料集」,建立「SQL資料集」。如下圖所示:
2)設定資料集名稱為「同步使用者」,資料連結選擇「FRDemoTW」,SQL 語句為:
select * from 同步使用者
2.4.3 同步使用者
1)管理者登入數據決策系統,點選「管理系統>使用者管理>所有使用者」,點選「同步使用者」。
跳出提示框「是否保留現有非同步資料,包括匯入/新增的使用者、部門職務、角色」,如下圖所示:
注1:本章是針對「之前從未進行過同步使用者」、「同步使用者未開啟狀態下執行首次同步操作」的資料更新規則。
若之前同步過使用者,在同步使用者開啟狀態下執行非首次同步操作將不會出現此節提示彈窗,也不會按照此節中更新規則進行同步。
注2:同步的使用者與「手動新增/匯入的使用者」可並存。
不同選擇對應的更新邏輯如下:
選擇 | 定義 |
---|---|
保留 | 如果現有使用者不在同步的伺服器資料集中,該使用者資訊和權限將被保留,不修改 如果現有使用者在伺服器資料集中(帳號相同):
|
清空 | 平台現有「手動新增/匯入的使用者」的帳號、姓名、密碼、手機、信箱、部門、職務、角色、權限均被刪除,重新同步使用者 |
注:根據選擇的更新邏輯,首次同步後有部分使用者資訊被更新。
之後能被自動更新的只有已變為同步類型的使用者。
之後的同步,資料集不能再改寫更新內建資料,否則將衝突報錯。
2)配置同步使用者。如下圖所示:
使用者來源選擇為:2.4.2 中準備的伺服器資料集「同步使用者」
密碼選擇為:password
加密方式選擇為:內建SHA加密
點選「確定」,同步使用者成功。如下圖所示:
2.5 效果預覽
使用者 a 在瀏覽器中存取連結:http://localhost:8075/webroot/login.html
在登入頁面輸入明文密碼:123456,點選「登入」,成功登入數據決策系統。如下圖所示:
注:範例動圖為了展示加密登入效果,在 2.2 節提供的程式碼基礎上新增了alert(url);等來查看頁面資訊,使用者可自行新增查看加密登入效果。
使用者點選「登入」按鈕後,前台會對使用者輸入登入資訊進行以下處理:
1)對輸入密碼進行 md5 加密,將最終得到的密文作為API入參。
範例:輸入密碼為:123456,md5 加密後得到密文:49BA59ABBE56E057。
2)呼叫前台單點登入API,將使用者資訊傳輸至數據決策系統進行登入驗證。
若傳輸的密碼與數據決策系統中所儲存的密碼一致,即可成功存取數據決策系統。如下圖所示: