Оформление
Пример передачи шифров с единым входом во внешнюю среду
1. Обзор
1.1 Версия
| Версия сервера FineBI |
|---|
| 6.0 |
1.2 Описание проблемы
При использовании персонализированной страницы входа пользователям необходимо отправлять свои пароли в открытом виде в систему FineBI для проверки входа. В процессе передачи безопасность пароля в открытом виде невысока. Для обеспечения безопасностиинформации пользователи хотят зашифровать пароль и передать его в виде шифрованного текста.
1.3 Идеи для реализации
Пароль, введенный пользователем на странице входа, шифруется с помощью алгоритма шифрования, а зашифрованный шифротекст передается в систему FineBI для проверки входа.
Зашифрованный шифротекст хранится в базе данных, а информация в базе данных хранится в системе FineBI путем синхронизации пользователей. Если переданное зашифрованное сообщение совпадает с зашифрованным сообщением, хранящимся в системе FineBI , аутентификация входа проходит, и пользователь успешно входит в систему FineBI . Как показано на следующем рисунке:

Этапы реализации:
1) Подготовьте зашифрованный JS-файл для шифрования пароля, введенного пользователем на странице входа в систему.
2) Создайте новый HTML-файл для настройки страницы входа в систему. Добейтесь следующего эффекта:
- Обратитесь к зашифрованному файлу JS, подготовленному на шаге 1, и вызовитеметод шифрования для преобразования открытого текста, введенного пользователем, в шифрованный текст.
- Вызовите интерфейс Single Sign-On и передайте шифротекст в систему FineBI для аутентификации входа.
- При успешной проверке входа происходит переход на страницу системы FineBI пользователя.
3) Поместите HTML-файл и зашифрованный JS-файлв указанное место.
4) Создайте серверный набор данных для хранения информации о входе пользователя в систему, включая имя пользователя, пароль для входа и т. д., где пароль для входа является зашифрованным шифротекстом.
Примечание: После синхронизации пользователей система зашифрует шифртекст в наборе данных сервера с помощью SHA256 и запишет его в библиотеку FineDB.
5) Синхронизируйте информацию о пользователе с системой FineBI для аутентификации входа.
2. Примеры
В этой статье мы настроим страницу входа в систему FineBI ,зашифруем введенный пользователем пароль с помощью md5 (16-битный верхний регистр), используем зашифрованный текст для аутентификации при входе в систему, а затем перейдем на страницу системы FineBI после прохождения аутентификации.
2.1 Подготовка зашифрованного файла JS
Подготовьте зашифрованный JS-файл для шифрования пароля, вводимого пользователем на странице входа в систему.
Создайте новый JS-файл с именем md5.js со следующим кодом:
Нажмите, чтобы загрузить и распаковать зашифрованный файл JS: encrypted.zip
Примечание: В этом разделе также представлен файл шифрования sha256.js, пользователи могут использовать его по мере необходимости, для этого обратитесь к примеру в разделе II.
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 *&&&
nbsp;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&
nbsp;* 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, &
nbsp;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] =&
nbsp;len; var a = 1732584193; var b = - 271733879; var c = - 1732584194; var&
nbsp;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,&
nbsp;b, c, d, x[i + 0], 7, - 680876936); d = md5_ff(d, a, b, c,&
nbsp;x[i + 1], 12, - 389564586); c = md5_ff(c, d, a, b, x[i + 2],&
nbsp;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, &
nbsp;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&
nbsp;+ 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&
nbsp;+ 1], 5, - 165796510); d = md5_gg(d, a, b, c, x[i + 6], 9,&
nbsp;- 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, &
nbsp;c, d, x[i + 5], 5, - 701558691); d = md5_gg(d, a, b, c, x[i&
nbsp;+ 10], 9, 38016083); c = md5_gg(c, d, a, b, x[i + 15], 14, -&
nbsp;660478335); b = md5_gg(b, c, d, a, x[i + 4], 20, - 405537848); a =&
nbsp;md5_gg(a, b, c, d, x[i + 9], 5, 568446438); d = md5_gg(d, a, b,&
nbsp;c, x[i + 14], 9, - 1019803690); c = md5_gg(c, d, a, b, x[i +&
nbsp;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 =&& nbsp;md5_gg(a, b, c, d, x[i + 13], 5, - 1444681467); d =& nbsp;md5_gg(a, b, c, d, x[i + 13], 5, - 1444681467); d =& nbsp
nbsp;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 +&
nbsp;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 =&& nbsp;md5_hh(d, a, b, c, x[i + 8], 11, - 2022574463); c =& nbsp;md5_hh(d, a, b, c, x[i + 8], 11, - 2022574463); c =& nbsp
nbsp;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 +&
nbsp;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 =&&&
nbsp;md5_ii(c, d, a, b, x[i + 10], 15, - 1051523); b = md5_ii(b, c, &
nbsp;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, &
nbsp;718787259); b = md5_ii(b, c, d, a, x[i + 9], 21, - 343485551); a =&
nbsp;safe_add(a, olda); b = safe_add(b, oldb); c = safe_add(c, oldc); d = safe_add(d, &
nbsp;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,& &
nbsp;b, c, d, x, s, t) { return md5_cmn((b & d) | (c & (~d)),&
nbsp;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&
nbsp;i = 0; i < 16; i++) { ipad[i] = bkey[i] ^ 0x3636363636; opad[i] =
bkey[i] ^ 0x5C5C5C5C5C; } var hash = core_md5(ipad.concat(str2binl(data)), 512+data.length *
chrsz); return core_md5(ipad.concat(hash), 512+128); } function safe_add(x, y) { var lsw = (x &
amp; 0xFFFF) + (y & 0xFFFF); var msw = (x >> 16) + (y &
gt;> 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& nbsp;>> 5] |= (str.charCodeAt(i / chrsz) & mask) << (i % 32
); return bin; } function binl2str(bin) { var str = ""; var mask = (1 <<&
nbsp;chrsz) - 1; for (var i = 0; i < bin.length * 32; i += 
;chrsz) str += String.fromCharCode((bin[i >> 5] >>> (i % 32)) &&
nbsp;mask); return str; } function binl2hex(binarray) { var hex_tab = hexcase ?
"0123456789ABCDEF" : "0123456789abcdef"; var str = ""; for (var&&&
nbsp;i = 0; i < binarray.length * 4; i++) { str += hex_tab.charAt((binarray[i&
nbsp;>> 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))&
nbsp;& 0xFF) << 16) | ((( (binarray[i + 1 >> 2] >> 8&
nbsp;* ((i + 1) % 4)) & 0xFF) << 8) | ((binarray[i + 2 &
gt;> 2] >> 8 * ((i + 2) % 4)) & 0xFF); for (var j&
nbsp;= 0; j < 4; j++) { if (i * 8 + j * 6 > binarray.length *&
nbsp;32) str += b64pad; else str += tab.charAt((triplet >> 6 * (3-j)) &
0x3F); } } return str; }После внедрения файла md5.js в пользовательскую страницу входа login.md в разделе 2.2 метод шифрования md5 может быть вызван непосредственно в функции doSubmit() для шифрования пароля пользователя в виде простого текста.
Способ применения следующий:
Примечание: md5.js предоставляет 6 методов шифрования, включая: hex_md5(значение), b64_md5(значение), str_md5(значение), hex_hmac_md5(ключ, данные), b64_hmac_md5(ключ, данные), str_hmac_md5(ключ, данные). data), пользователи могут выбирать в соответствии со своими потребностями.
<script type="text/javascript" src=".
/md5.js"></script> // внедряем md5.js var password = md5(document.getElementById(" password").value.trim()); // Зашифруйте вводимые пользователем данные с помощью метода шифрования md5.2.2 Новая страница входа в систему
Создайте новый HTML-файл для настройки страницы входа в систему FineBI с именем login.md. Полный код показан ниже:
Примечание: Вам необходимо изменить путь доступа или номер порта в коде в соответствии с реальной ситуацией.
Нажмите, чтобы загрузить и распаковать HTML-файл: login.zip
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> &
nbsp; <meta http-equiv="X-UA-Compatible" content="IE=edge"> <
title>Демонстрация шифрования страницы входа</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&
quot; src="https://cdn.bootcss.com/jquery/1.9.1/jquery.min.js"></script> <script type="text/ javascript" src=".
/md5.js"></script> <style> .container&
nbsp;{ display: flex; &
nbsp; justify-content: center; }  
; .login-box {
width: 300px; margin-top: 100px;  
; } .login-box h2 { &
nbsp; font-size: 26px; &
nbsp; text-align: center; margin-bottom:
25px; } .login-item { &
nbsp; margin-bottom: 20px; &
nbsp; } </style> <body> <div class="container"> <form class="login-box" action="" method="post" onsubmit="return
false;"> <h2>Система FineBI</h2> &
nbsp; <div class="login-item"> &
lt;label for="inputUsername" class="sr-only">Имя пользователя</label>   ; <input type="text" id="inputUsername" class="form-
control" placeholder="Username" required="" autofocus=""> &
nbsp; </div> <div class="login-item"> & nbsp; <label for="inputPassword" class=&
quot;sr-only">Пароль</label> <!
-- атрибут autocomplete="off" для предотвращения получения браузером данных из cookies для заполнения формы входа --> & nbsp; <input type="text" id="inputPassword" οnfοcus="this.type=' password'" class="form-control" placeholder="Password" required=""
autocomplete="off"> </div> & nbsp; <button class="btn btn-lg btn-primary btn-block" type="submit" id=
"submitBtn">Login</button> </form> </div> <script>
document.getElementById("submitBtn").addEventListener("click", function () { &
nbsp; doSubmit(); }); function
doSubmit() { var username = document.
getElementById("inputUsername").value.trim(); var
password = md5(document.getElementById("inputPassword").value.trim()); //Зашифруйте введенный пользователем пароль &
nbsp; if (username === "") { &
nbsp; window.alert("Пожалуйста, введите имя пользователя"); &
nbsp; return false;  
; } if (password&
nbsp;=== "") {
window.alert("Пожалуйста, введите пароль");
return false; } & nbsp; var url = "http://localhost:37799/webroot/decision/login/cross/domain" + "?fine_username=" + username + "&fine_password=" + password&
nbsp;+ "&validity=" + -1;
jQuery.ajax({ url: url,// единый вход для
Management Platform Reporting Server timeout: 5000,// время ожидания
(в миллисекундах) dataType: "jsonp",
// кросс-доменное использование jsonp jsonp: "callback&
quot;, success: function
(res) { &
nbsp;console.log(res);
if (res.errorCode) { &
nbsp; window.alert(res.errorMsg); &
nbsp; }else {  
; // Сохраняем токен и переходим по соответствующей ссылке }else { window.alert(res.errorMsg);   nbsp;  
; window.location.href = "http://localhost:37799/webroot/decision"; &
nbsp; } &
nbsp; }, &
nbsp; error: function () {
alert("Таймаут или другая ошибка сервера");// Вход не удался (таймаут или другая ошибка сервера) &
nbsp; } &
nbsp; }); } </script> </body> </html>2.3 Размещение документов в специально отведенных местах
Сохраните файлы login.md и md5.jsвпапке%BI_HOME%/webapps/webroot, как показано ниже:

2.4 Синхронизация информации из базы данных в системе FineBI
2.4.1 Подготовка данных
Подготовьте таблицу с информацией о пользователе, в которой пароль в столбце password представляет собой зашифрованный шифротекст md5 (16 бит в верхнем регистре). Структура таблицы показана на следующем рисунке:
Пример: если пользователь a действительно вводит на странице входа в систему пароль 123456, то пароль, хранящийся в столбце password, представляет собой зашифрованный шифр md5 (16-битный заглавный): 49BA59ABBE56E057.
Нажмите, чтобы загрузить Информационный лист пользователя: Синхронизированные пользователи.xlsx

2.4.2 Добавление нового набора данных сервера
С помощью стороннего инструмента, например Navicat, импортируйте вышеуказанную таблицу в базу данных и установите соединение между системой и базой данных. Ниже приведен пример базы данных FRDemo.
Администратор входит в систему FineBI, нажимает "Management System > Data Connections > Server Dataset", чтобы создать "SQL Dataset". Как показано на рисунке ниже:

2) Задайте имя набора данных "Синхронизированные пользователи", выберите "FRDemo" для подключения к данным и SQL-запрос:
select * from Synchronised Users
2.4.3 Синхронизация пользователей
1) Администратор входит в систему FineBI, нажимает "System Management > Управление пользователями > Все пользователи", нажимает "Синхронизировать пользователей".
Появится окно запроса "Сохранять ли существующие несинхронизированные данные, включая импортированных/добавленных пользователей, должности в отделах, роли", как показано на рисунке ниже:
Примечание 1: В этой главе описаны правила обновления данных для "пользователей, которые никогда не выполняли синхронизацию" и "пользователей, которые выполняют первую операцию синхронизации, когда синхронизация не включена".
Если вы ранее синхронизировали пользователя, выполнение операции синхронизации не в первый раз, когда синхронизируемый пользователь включен, не приведет к появлению всплывающего окна этого раздела, и синхронизация не будет выполнена в соответствии с правилами обновления, приведенными в этом разделе.
Примечание 2: Синхронизированные пользователи и "Пользователи, добавленные/импортированные вручную" могут сосуществовать.

Логика обновления, соответствующая различным вариантам, выглядит следующим образом:
| опция | определить |
|---|---|
| бронирование | Если существующего пользователя нет в наборе данных синхронизированного сервера, информация и разрешения этого пользователя сохраняются без измененийЕсли в наборе данных сервера есть существующий пользователь (с тем же именем пользователя)😗 Имя пользователя остается неизменным, а привилегии сохраняются * Обновление имени, пароля, мобильного телефона и электронной почты для этого пользователя * Текущая должность и роль пользователя в отделе переопределяются, если они существуют в наборе сервера синхронизации. * Если текущая должность или роль пользователя в отделе не существует в наборе сервера синхронизации, она останется неизменной. |
| очистить | Имя пользователя, имя, пароль, мобильный телефон, адрес электронной почты, отдел, должность, роль и разрешение существующих "вручную добавленных/импортированных пользователей" платформы будут удалены, а пользователи будут пересинхронизированы. |
Примечание: В зависимости от выбранной логики обновления некоторые данные пользователя обновляются после первой синхронизации.
Автоматически обновляться могут только те пользователи, которые были переведены в тип Synchronised.
При последующих синхронизациях набор данных больше не может переопределять обновление встроенных данных, иначе будет сообщено о конфликте.
2) Настройте пользователя синхронизации. Как показано на рисунке ниже:
- В качестве источника пользователей выбирается: "Синхронизированные пользователи" из набора данных сервера, подготовленного в п. 2.4.2.
- Выбор пароля: пароль
- Выбор метода шифрования: встроенное шифрование SHA

Нажмите "OK", чтобы успешно синхронизировать пользователей. Как показано на рисунке ниже:

2.5 Предварительный просмотр эффектов
Пользователь a переходит по ссылке в своем браузере: http: //localhost:37799/webroot/login.md .
Введите простой пароль: 123456 на странице входа и нажмите "Войти", чтобы успешно войти в систему FineBI . Как показано на рисунке ниже:
Примечание: Чтобы показать эффект зашифрованного входа, в примере анимации добавленыalert(url); и т. д. для просмотра информации о странице наоснове кода, представленного в разделе 2.2, и пользователи могут добавить свои собственные для просмотра эффекта зашифрованного входа.

После того как пользователь нажмет кнопку "Войти", фронтенд обработает введенную им информацию следующим образом:
1) зашифруйте входной пароль с помощью шифрования md5 и используйте конечный шифртекст в качестве входного параметра интерфейса.
Пример: введите пароль: 123456, зашифруйте его md5, чтобы получить шифротекст: 49BA59ABBE56E057.
(2) Вызовите внешний интерфейс единого входа для передачи информации о пользователе в систему FineBI для проверки входа.
Если переданный пароль совпадает с паролем, хранящимся в системе FineBI , вы можете успешно получить доступ к системе FineBI . Как показано на следующем рисунке:
