Skip to content

Пример кода RSA для однократной регистрации на бэкенде

1. Обзор

1.1 Версия

Версии сервера FineBIПлагин единого входа в системуФункциональные изменения
6.0V1.1.1-
6.0.10V1.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"; //со страницы конфигурации плагина &nbsp ; String publicKey = key == null ?  
   
  
 defaultKey : key; //зашифрованный ssoToken, может быть расшифрован в интерфейсе foreground для проверки &nbsp ; String encryptedToken = key == null ?  
 nbsp; String encrypt = encrypt(username, publicKey); &nbsp  
   
; System.out.println("зашифрованное имя пользователя: " + encrypt);   //кодированное имя пользователя: " + encrypt); &nbsp  
 nbsp; //кодируем после токена, можно разместить прямо на url для одной точки String encode&nbsp  
;= URLEncoder.encode(encrypt, "UTF-8"); System.out.println(& & &  
   
  
   
  
 quot;ssoToken: " + encode); } /** & nbsp; * Метод шифрования.  
  
  
 * * @param plainText Текст, который нужно зашифровать &nbsp.  
  
;* @param customPublicKey Публичный ключ, может быть получен на странице конфигурации плагина * @return base64 encoded encrypted string &nbsp  
;*/ 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)&nbsp  
  
;{ 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; } &nbsp.  
; if (endIndexExclusive > array.length) { &nbsp; return null; }  
 nbsp; endIndexExclusive = array.length; &  
   
 nbsp; } &  
 nbsp; int newSize = endIndexExclusive - startIndexInclusive; &  
 nbsp; if (newSize <= 0) { &nbsp  
 nbsp; return new byte[0]; & nbsp; } else { &nbsp  
 nbsp; } else { &nbsp  
 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(); &nbsp  
   
; } protected void  
 decodeLineSuffix(PushbackInputStream var1, OutputStream var2) throws Exception { &  
   
 nbsp; } protected void decodeAtom(  
 PushbackInputStream var1, OutputStream var2, int var3) throws Exception { &nbsp  
; throw new Exception(); &  
   
 nbsp;} protected int readFully(InputStream var1, byte[] &  
 nbsp;var2, int var3, int var4) throws Exception { &nbsp; for(int var5); &nbsp;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; } &nbsp  
  
   
; 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) { &nbsp  
; try { &nbsp ; int var6 = this.decodeLinePrefix(var5,& nbsp;var2;)  
   
 nbsp;var2); &nbsp  
; int var3; & nbsp; for(var3 = 0; var3 + this.bytesPerAtom() < var6; var3 += this.  
 bytesPerAtom()) {   
 this.decodeAtom(var5, var2, this.bytesPerAtom()); &nbsp var4 +=  
 this.bytesPerAtom(); &nbsp ; }  
   
 nbsp; } &  
 nbsp; if (var3 + this.bytesPerAtom() == var6) { this.decodeAtom(var5, var2, &   
 nbsp; this.bytesPerAtom()); &  
 nbsp; var4 += this.bytesPerAtom(); &  
 nbsp; } else { &nbsp ; 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); &nbsp  
  
   
; return var2.toByteArray(); } &nbsp  
 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)); } &nbsp  
   
   
; } } static class BASE64Decoder extends CharacterDecoder&  
 nbsp;{ private static final char[] pem_array = new& nbsp;char[]{'A', 'B', 'C', 'D', 'E', 'F', 'G&#39 ;, 'H', 'I', 'J', 'K', 'L', 'M', 'N',& nbsp;'O', 'P', 'Q', 'R', 'S', 'T', 'U',&nbsp ; 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', &#nbsp. 39;c', 'd', 'e', 'f', 'g', 'h', 'i', 'j ', 'k', 'l', 'm', 'n', 'o', 'p', 'q&#39 ;, 'r', 's', 't', 'u', 'v', 'w', 'x',& nbsp;'y', 'z', '0', '1', '2', '3', '4',&nbsp  
;'5', '6', '7', '8', '9', '+', '/'}; & nbsp; private static final byte[] pem_convert_array = new  
  
   
 byte[256]; byte[] decode_buffer = new byte[4]; &nbsp  
  
   
; public BASE64Decoder() { } &nbsp  
 nbsp; protected int bytesPerAtom() { &nbsp; 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; &nbsp  
; byte var7 = -1; &nbsp; byte var7 = -1; &nbsp  
 nbsp; byte var8 = -1; if (var3&  
 nbsp;< 2) { throw&nbsp  
;new Exception("BASE64Decoder: Not enough bytes for an atom."); &  
 nbsp; } else { &nbsp  
; 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; &nbsp  
;case 4: & nbsp; var8 = pem_convert_array[this.decode_buffer[3] & 255]  
; &  
 nbsp; case 3: &nbsp ; var7 = pem_convert_array[this.decode_buffer[2] &  
 amp; 255]; &  
 nbsp; case 2: &nbsp ; var6 = pem_convert_array[this.decode_  
 буфер[1] & 255]; & nbsp; var5 = pem_convert_array[this.decode_buffer[0]&  
 nbsp; & 255]; &  
 nbsp; по умолчанию: &  
 nbsp; switch(var3) { & nbsp; &nbsp  
; case 2: & nbsp; &nbsp ; var2.write((byte)(var5 << 2 & 252 | var6 >>> 4 & 3  
 )); &  
 nbsp; break; &nbsp nbsp; break; &nbsp  
 nbsp; case 3: &nbsp case 3: &nbsp ;&nbsp; case 3: &nbsp  
 var2.write((byte)(var5 << 2 & 252 | var6 >>> 4 & 3)); & nbsp; &nbsp ; var2.write((byte)(var6 << 4&  
 nbsp;& 240 | var7 >>> 2 & 15)); &nbsp nbsp; break; &nbsp  
 nbsp; break; &nbsp  
; case 4: & nbsp; &nbsp ; var2.write((byte)(var5 << 2 &  
 amp; 252 | var6 >>> 4 & 3)); & nbsp; &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; } } &  
  
 nbsp; static { int var0; & nbsp; for(var0 = 0; var0 < 255; ++var0)&nbsp  
;{ 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, как показано на следующем рисунке:

Примечание: Значение после зашифрованного имени пользователя - это зашифрованное имя пользователя.

13.png

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 этой статьи, будут сгенерированы три файла классов. Это показано на рисунке ниже:

1641367340608312.png

1) Функция установки тайм-аута ssoToken не включена

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

12.png

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 с поддержкой таймаута:

13.png