Оформление
Пример кода RSA для однократной регистрации на бэкенде
1. Обзор
1.1 Версия
| Версии сервера FineBI | Плагин единого входа в систему | Функциональные изменения |
|---|---|---|
| 6.0 | V1.1.1 | - |
| 6.0.10 | V1.2.2 | Адаптация к новым визуальным стилям |
1.2 Сценарии применения
При использовании плагина Backend Single Sign-On Plugin для шифрования имени пользователя необходимо вручную зашифровать имя пользователя, чтобы сгенерировать ssoToken, а затем зайти на сайт http://ip:port/工程名/decision?ssoToken=xxx进行单点登录 через браузер . Пользователи хотели бы устранить ручной процесс шифрования и повысить эффективность шифрования.
1.3 Функциональный профиль
В этой статье описывается, как автоматически генерировать ssoToken с помощью кода, и приводится пример кода на Java.
1.4 Необходимые условия для использования
Требуется установка плагина backend single sign-on, плагин подробно описан в: backend single sign-on plug-in
2. Операционные шаги
2.1 Генерация ключа RSA
Супервизор входит в платформу и нажимает "Управление системой > Управление системой > Integration Backend Single Sign-On > Generate RSA Key", как показано на рисунке ниже:
Примечание: Открытый ключ, созданный на этом шаге, будет использоваться в разделе 2.2 данного документа.

2.2 Создание нового Java-файла
Создайте новый Java-файл с именем RsaEncrypt.java. Полный код Java показан ниже:
import org.jetbrains.annotations.Nullable; import javax.crypto.BadPaddingException; import javax.crypto.Cipher; import
javax.crypto.IllegalBlockSizeException; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream.
import java.io.InputStream; import java.io.OutputStream; import java.io.PushbackInputStream; import java.io.
UnsupportedEncodingException; import java.net.URLEncoder; import java.nio.ByteBuffer; import java.nio.charset.
StandardCharsets; import java.security.Key; import java.security.KeyFactory; import java.security.PublicKey; import&
nbsp;java.security.spec.X509EncodedKeySpec; import java.util.Base64; /** * @author Afly *.
created on 2021-11-09 */ public class RsaEncrypt { private static&
nbsp;final int FRAGMENT_LENGTH = 245; public static void main(
String[] args) throws UnsupportedEncodingException { String&
nbsp;text = System.getProperty("text"); String key =&
nbsp;System.getProperty("publicKey"); String username = text == null ?
"Alice" : text; String defaultKey = "
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArai/XKZ0fdbL96/r4g4dT3hgVVVcDjTno\r\n" + &
nbsp; "LJ90c4AEQ8WSYA2vq/copvU6EuV0If4B35fdsC9mfeuHttUir/7tdWH/SAUyLaw2wnG1YsE+Asgy\r\n" + & & nbsp; "TXpkgPXaIwLqRM0KjfRrG1K1iHAOv8lftycsnsqEjgZ36k/Uqr291Pdp5pFTx+nCgPYM57RunKts\r\n&
quot; + "iZjXCulhHJxlTXShMt/
1lxdp52EWkJsjaBWH2sv5p7GXv7FXyWfKxY7WlgzBfMBCX+pMfYSjRFC9\r\n" + & &
quot;PY4kpoZHdGflHCbzpcoRCqyWboZKHK/eCF5CpfFUzW7+M52y57PJMCen1G6+AZNxSqw43TN25h1b\r\n" + & &
nbsp; "SfKQNQIDAQAB"; //со страницы конфигурации плагина   ; String publicKey = key == null ?
defaultKey : key; //зашифрованный ssoToken, может быть расшифрован в интерфейсе foreground для проверки   ; String encryptedToken = key == null ?
nbsp; String encrypt = encrypt(username, publicKey);  
; System.out.println("зашифрованное имя пользователя: " + encrypt); //кодированное имя пользователя: " + encrypt);  
nbsp; //кодируем после токена, можно разместить прямо на url для одной точки String encode 
;= URLEncoder.encode(encrypt, "UTF-8"); System.out.println(& & &
quot;ssoToken: " + encode); } /** & nbsp; * Метод шифрования.
* * @param plainText Текст, который нужно зашифровать  .
;* @param customPublicKey Публичный ключ, может быть получен на странице конфигурации плагина * @return base64 encoded encrypted string  
;*/ public static String encrypt(String plainText, String
customPublicKey) { return encrypt(plainText, string2PublicKey(
customPublicKey)); } public static byte[] encrypt(byte[]
plainTextData, Key publicKey) { if (plainTextData.length&
nbsp;== 0) { return plainTextData; &
nbsp; } try {
Cipher c1 = Cipher.getInstance("RSA"); &
nbsp; c1.init(Cipher.ENCRYPT_MODE, publicKey); &
nbsp; return dealEncryptFragment(plainTextData, c1); &
nbsp; } catch (Exception e) { e.
printStackTrace(); } return
null; } public static String encrypt(String plainText,&
nbsp;Key publicKey) { if (plainText == null ||&
quot;".equals(plainText)) { return plainText
; } byte[] publicEncrypt =
encrypt(plainText.getBytes(StandardCharsets.UTF_8), publicKey); return&
nbsp;Base64.getEncoder().encodeToString(publicEncrypt); } public static&
nbsp;PublicKey string2PublicKey(String pubStr) { try { &
nbsp; byte[] keyBytes = base642Byte(pubStr); X509EncodedKeySpec keySpec = new
X509EncodedKeySpec(keyBytes); KeyFactory keyFactory&
nbsp;= KeyFactory.getInstance("RSA"); return
keyFactory.generatePublic(keySpec); } catch (Exception e) 
;{ e.printStackTrace();
} return null; } &
nbsp;public static byte[] base642Byte(String base64Key) throws Exception { &
nbsp; BASE64Decoder decoder = new BASE64Decoder(); &
nbsp; return decoder.decodeBuffer(base64Key); } private static& nbsp;byte[] dealEncryptFragment(byte[] data, Cipher cipher) throws IllegalBlockSizeException,
BadPaddingException { byte[] result = new byte[]{}; &
nbsp; int i; for (i =
0; i < data.length; i += FRAGMENT_LENGTH) { &
nbsp; byte[] fragment = subarray(data, i, i + FRAGMENT_LENGTH); &
nbsp; byte[] update = cipher.doFinal(fragment); &
nbsp; result = addAll(result, update);
} return result; } & nbsp; public static byte[] subarray(@Nullable byte[] array, int startIndexInclusive, int endIndexExclusive)
int endIndexExclusive) { if (array == null) { &
nbsp; return null;
} else { if (startIndexInclusive
< 0) {
startIndexInclusive = 0; }  .
; if (endIndexExclusive > array.length) { return null; }
nbsp; endIndexExclusive = array.length; &
nbsp; } &
nbsp; int newSize = endIndexExclusive - startIndexInclusive; &
nbsp; if (newSize <= 0) {  
nbsp; return new byte[0]; & nbsp; } else {  
nbsp; } else {  
nbsp; byte[] subarray = new byte[newSize]; &
nbsp; System.arraycopy(array, startIndexInclusive, subarray, 0, newSize); &
nbsp; return subarray; &
nbsp; } } } &
nbsp; public static byte[] addAll(@Nullable byte[] array1, @Nullable byte...
array2) { if (array1 == null) { &
nbsp; return clone(array2); }&
nbsp;else if (array2 == null) {
return clone(array1); } else { &
nbsp; byte[] joinedArray = new byte[array1.length + array2.length]; & nbsp; System.arraycopy(array1, 0, joinedArray, 0, &
nbsp;array1.length); System.arraycopy(array2, 0,
joinedArray, array1.length, array2.length);
return joinedArray; } }
public static byte[] clone(@Nullable byte[] array) { return array == null ?
null : (byte[]) array.clone(); } static abstract&
nbsp;class CharacterDecoder { public CharacterDecoder() {
} protected abstract int&
nbsp;bytesPerAtom(); protected abstract int bytesPerLine(); &
nbsp; protected void decodeBufferPrefix(PushbackInputStream var1,&
nbsp;OutputStream var2) throws Exception { } & nbsp; protected void decodeBufferSuffix(PushbackInputStream var1, OutputStream&
nbsp;var2) throws Exception { } & nbsp; protected int decodeLinePrefix(PushbackInputStream var1, OutputStream var2) throws&
nbsp;Exception { return this.bytesPerLine();  
; } protected void
decodeLineSuffix(PushbackInputStream var1, OutputStream var2) throws Exception { &
nbsp; } protected void decodeAtom(
PushbackInputStream var1, OutputStream var2, int var3) throws Exception {  
; throw new Exception(); &
nbsp;} protected int readFully(InputStream var1, byte[] &
nbsp;var2, int var3, int var4) throws Exception { for(int var5); throw new Exception().
nbsp; for(int var5 = 0; var5 < var4; ++var5) {
int var6 = var1.read(); & nbsp; for(int var6 = 0; var5 < var4; ++var5) {
nbsp; if (var6 == -1) { & nbsp; return var5& nbsp;== 0 ?
-1 : var5; } & nbsp; var2[var5 + var3] =&
nbsp;(byte)var6; }  
; return var4; } & nbsp; public void decodeBuffer(InputStream var1, OutputStream var2) throws&
nbsp;Exception { int var4 = 0; & nbsp; PushbackInputStream var5 = new
PushbackInputStream(var1); this.decodeBufferPrefix(var5,& nbsp;var2); this.decodeBufferPrefix(var5,& nbsp;var2); this.
nbsp;var2); while(true) {  
; try {   ; int var6 = this.decodeLinePrefix(var5,& nbsp;var2;)
nbsp;var2);  
; int var3; & nbsp; for(var3 = 0; var3 + this.bytesPerAtom() < var6; var3 += this.
bytesPerAtom()) {
this.decodeAtom(var5, var2, this.bytesPerAtom());   var4 +=
this.bytesPerAtom();   ; }
nbsp; } &
nbsp; if (var3 + this.bytesPerAtom() == var6) { this.decodeAtom(var5, var2, &
nbsp; this.bytesPerAtom()); &
nbsp; var4 += this.bytesPerAtom(); &
nbsp; } else {   ; this.decodeAtom(var5, var2, var6 - var3); this.decodeAtom(var5, var6 - var3)
var2, var6 - var3);
var4 += var6 - var3;
} &
nbsp; this.decodeLineSuffix(var5, var2); &
nbsp; } catch (Exception var8) { & nbsp; this.
decodeBufferSuffix(var5, var2); & nbsp; return; & nbsp; this.
nbsp; return; &
nbsp; } } &
nbsp; public byte[] decodeBuffer(String var1) throws
Exception { byte[] var2 = new byte
[var1.length()]; var1.getBytes(0, var1.length(),
var2, 0); ByteArrayInputStream var3 =
new ByteArrayInputStream(var2); ByteArrayOutputStream&
nbsp;var4 = new ByteArrayOutputStream();
this.decodeBuffer(var3, var4); return var4.
toByteArray(); } public
byte[] decodeBuffer(InputStream var1) throws Exception { &
nbsp; ByteArrayOutputStream var2 = new ByteArrayOutputStream();
this.decodeBuffer(var1, var2);  
; return var2.toByteArray(); }  
nbsp; public ByteBuffer decodeBufferToByteBuffer(String var1) throws Exception { &
nbsp; return ByteBuffer.wrap(this.decodeBuffer(var1));
} public ByteBuffer
decodeBufferToByteBuffer(InputStream var1) throws Exception { &
nbsp; return ByteBuffer.wrap(this.decodeBuffer(var1)); }  
; } } static class BASE64Decoder extends CharacterDecoder&
nbsp;{ private static final char[] pem_array = new& nbsp;char[]{'A', 'B', 'C', 'D', 'E', 'F', 'G' ;, 'H', 'I', 'J', 'K', 'L', 'M', 'N',& nbsp;'O', 'P', 'Q', 'R', 'S', 'T', 'U',  ; 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', &#nbsp. 39;c', 'd', 'e', 'f', 'g', 'h', 'i', 'j ', 'k', 'l', 'm', 'n', 'o', 'p', 'q' ;, 'r', 's', 't', 'u', 'v', 'w', 'x',& nbsp;'y', 'z', '0', '1', '2', '3', '4', 
;'5', '6', '7', '8', '9', '+', '/'}; & nbsp; private static final byte[] pem_convert_array = new
byte[256]; byte[] decode_buffer = new byte[4];  
; public BASE64Decoder() { }  
nbsp; protected int bytesPerAtom() { return 4; }
nbsp; return 4; } &
nbsp; protected int bytesPerLine() { &
nbsp; return 72; } protected void decodeAtom(PushbackInputStream var1, OutputStream var2, int var3) throws&
nbsp;Exception { byte var5 = -1; &
nbsp; byte var6 = -1;  
; byte var7 = -1; byte var7 = -1;  
nbsp; byte var8 = -1; if (var3&
nbsp;< 2) { throw 
;new Exception("BASE64Decoder: Not enough bytes for an atom."); &
nbsp; } else {  
; int var4; &
nbsp; do { &
nbsp; var4 = var1.read();
if (var4 == -1) { &
nbsp; throw new Exception(); &
nbsp; } & nbsp; } while(var4 == 10 ||
var4 == 13); this.
decode_buffer[0] = (byte)var4;
var4 = this.readFully(var1, this.decode_buffer, 1, var3 - 1); &
nbsp; if (var4 == -1) { & nbsp; throw new Exception
(); } else { & nbsp; if (var3 >
3 && this.decode_buffer[3] == 61) { & nbsp; var3 = 3; this.decode_buffer[3] == 61) { & nbsp; var3 = 3; this.decode_buffer[3] == 61) { & nbsp; throw new Exception (); }
nbsp; var3 = 3; &
nbsp; } & nbsp; if (var3 >
2 && this.decode_buffer[2] == 61) { &
nbsp; var3 = 2; &
nbsp; } &
nbsp; switch(var3) { & nbsp;  
;case 4: & nbsp; var8 = pem_convert_array[this.decode_buffer[3] & 255]
; &
nbsp; case 3:   ; var7 = pem_convert_array[this.decode_buffer[2] &
amp; 255]; &
nbsp; case 2:   ; var6 = pem_convert_array[this.decode_
буфер[1] & 255]; & nbsp; var5 = pem_convert_array[this.decode_buffer[0]&
nbsp; & 255]; &
nbsp; по умолчанию: &
nbsp; switch(var3) { & nbsp;  
; case 2: & nbsp;   ; var2.write((byte)(var5 << 2 & 252 | var6 >>> 4 & 3
)); &
nbsp; break;   nbsp; break;  
nbsp; case 3:   case 3:   ; case 3:  
var2.write((byte)(var5 << 2 & 252 | var6 >>> 4 & 3)); & nbsp;   ; var2.write((byte)(var6 << 4&
nbsp;& 240 | var7 >>> 2 & 15));   nbsp; break;  
nbsp; break;  
; case 4: & nbsp;   ; var2.write((byte)(var5 << 2 &
amp; 252 | var6 >>> 4 & 3)); & nbsp;   ; var2.write((byte)(var5 << 2 & amp; 252 | var6 >>> 4 & 3)); nbsp; var2.write((byte)(var6 << 4 & 240 | var7 >>&
gt; 2 & 15)); & nbsp; var2.write(
(байт)(var7 << 6 & 192 | var8 & 63)); & nbsp;  
;} } &
nbsp; } &
nbsp; } } &
nbsp; static { int var0; & nbsp; for(var0 = 0; var0 < 255; ++var0) 
;{ pem_convert_array[var0] =&
nbsp;-1; } &
nbsp; for(var0 = 0; var0 < pem_array.length; ++var0) { & nbsp; pem_convert_array[pem_array[var0]] =
(byte)var0; } &
nbsp; } } }Необходимо обратить внимание на следующие моменты:
1) String username = text == null ? "Alice" : text; Alice в коде нужно заменить на имя пользователя проекта, который вы хотите зашифровать.
(2) Значение после String defaultKey должно быть заменено на открытый ключ, сгенерированный в вашем собственном проекте, пожалуйста, обратитесь к разделу 2.1 для метода генерации открытого ключа.
(3) Если вы включили функцию "ssoToken timeout setting", вам нужно заменить кодString text = System.getProperty("text"); на следующий код, где username - имя пользователя, issueTime - текущая миллисекундная временная метка. issueTime - текущая миллисекундная временная метка. Как показано на рисунке ниже:
Срок действия ssoToken истекает на основе входящей метки временипосле достижения входящей метки времени + "System Admin > Login > Login Timeout Time ".
String text = "{\"имя пользователя\":\"Алиса\",\"время выдачи\":1640832102097}";";
2.3 Компиляция Java-кода
Скомпилируйте Java-программу, которая сгенерирует зашифрованное имя пользователя, ssoToken, как показано на следующем рисунке:
Примечание: Значение после зашифрованного имени пользователя - это зашифрованное имя пользователя.

2.4 Эффекты просмотра
2.4.1 Проверьте правильность процесса шифрования и дешифрования
Supervisor войдите в платформу, нажмите "Management System > System Management > Integration Backend Single Sign-On ", введите сгенерированное зашифрованное имя пользователя в поле " Decryption Test ", нажмите кнопку " Decode ", если вы можете успешно расшифровать имя пользователя, это означает, что процесс шифрования и дешифрования правильный. Если имя пользователя может быть успешно расшифровано, это означает, что процесс шифрования и дешифрования выполнен правильно:

Если включен параметр "ssoToken Timeout Setting", если зашифрованное имя пользователя может быть успешно расшифровано, значит, процесс шифрования и дешифрования выполнен правильно. Как показано на рисунке ниже:

2.4.2 Единый вход на задней панели с помощью ssoToken
Браузеры переходят по ссылке: http://ip:port/工程名/decision?ssoToken=xxxдля однократного входа в бэкэнд с зашифрованными именами пользователей. Как показано на рисунке ниже:

3. условия
Вы можете запустить параметр text, publicKey, например : java -Dtext=text -DpublicKey=public key RsaEncrypt зашифрует пользовательский текст и открытый ключ, другие вызовы проекта могут быть вызваны напрямую RsaEncrypt#encrypt(java.lang.String, java. lang.String) для выполнения urlencode по мере необходимости.
После компиляции кода, приведенного в разделе 2.2 этой статьи, будут сгенерированы три файла классов. Это показано на рисунке ниже:

1) Функция установки тайм-аута ssoToken не включена
- Если вы компилируете код из раздела 2.2 этой статьи напрямую, cmd в каталог, где находится файл класса, выполните java -Dtext=username RsaEncrypt, чтобы сгенерировать зашифрованное имя пользователя, ssoToken.
- Если вы добавите имя пакета в код в разделе 2.2, например package;, вам нужно перейти в каталог, соответствующий имени пакета, и выполнить java -Dtext=username package.RsaEncrypt для генерации зашифрованного имени пользователя и ssoToken, как показано на следующем рисунке:

2) Включите функцию установки тайм-аута ssoToken
Примечание: В следующем исполняемом операторе username - это имя пользователя, а issueTime - текущая миллисекундная метка времени; следующий исполняемый оператор генерирует только полезные ssoTokens.
- Если вы компилируете код из раздела 2.2 напрямую, зайдите в каталог, где находится файл класса, и выполните java -Dtext="{\"имя пользователя\": \"1\",\"issueTime\": 1640832102097}& ". quot; RsaEncrypt для генерации ssoToken с поддержкой таймаута.
- Если вы добавили имя пакета в код в разделе 2.2, например package;, то вам нужно перейти в каталог, соответствующий имени пакета, и выполнить java -Dtext="{\"username\": \"1\",\"issueTime\": 1640832102097}" package.RsaEncrypt для генерации ssoToken с поддержкой таймаута. 1640832102097}" имя пакета.RsaEncrypt для генерации ssoToken с поддержкой тайм-аута. RsaEncrypt может генерировать ssoToken с поддержкой таймаута:
