本文為您介紹Dataphin BPMS支援對接第三方審批流,包括開放了哪些介面能力,如何接入審批能力以及審批案例等內容。
前提條件
已在Dataphin系統配置審批設定,如何配置,詳情請參見審批設定。營運租戶參見審批設定中選擇審批系統的其他配置項。
審批介面
{url}:為第三方審批流對接地址,http(s)://{url}為提交審批申請URL。
accessToken:調用服務端API的憑證。Dataphin頁面自動產生,或使用者產生填入Dataphin。
串連測試
請求方式:POST。
請求地址:http(s)://{url}/dataphin/bpms/check/connect。
請求時序圖

Query參數
參數名稱
參數類型
描述
accessToken
String
調用服務端API的憑證。
Dataphin頁面自動產生,或使用者產生填入Dataphin。如:6d1bxxxx。
timestamp
String
單位毫秒,資訊發送時間戳記。如:1654156836531。
Body參數
checkEvent(String):檢查事件為串連測試。如:connectivity。
返回參數
checkResult(String):檢查結果:成功,僅當傳回值為success時,認定為成功。其他值均被認為測試連接失敗。如:success。
提交審批
請求方式:POST。
請求地址:http(s)://{url}/dataphin/bpms/processinstance/create。
提交審批的時序圖

Query參數
參數名稱
參數類型
描述
accessToken
String
調用服務端API的憑證。
Dataphin頁面自動產生,或使用者產生填入Dataphin。如:6d1bxxxx。
timestamp
String
單位毫秒,資訊發送時間戳記。如:1654156836531。
Body參數
參數名稱
參數類型
描述
applyId
String
Dataphin審批單Id。如:1223。
title
String
Dataphin審批單標題。如:dataphin bpms。
content
String
Dataphin審批單內容。如:bpms content。請參見審批訊息內容中繼資料描述。
type
String
審批單類型:APPROVAL_DOC_TYPE。
代碼審核:CODE_REVIEW。
發布管控:PUBLISH。
業務規劃:BIZ_PLANNING。
許可權審批:AUTH。
預設:DEFAULT。
templateCode
String
審批模板code,可為空白,與頁面配置有關。
審批訊息內容中繼資料描述
參數名稱
參數類型
描述
resourceType
String
審批任務類型,為枚舉值,包含以下的類型:
PhysicalTable:物理表。
LogicTable:邏輯表。
MetaTable:即時元表。
MirrorTable:鏡像表。
Fun:函數。
DataSource:資料來源。
FeatureConfig:功能許可權配置。
OSAPP:資料服務APP。
OSAPI:資料服務API 。
OSLogicUnit:資料服務單元。
OSDS:資料服務資料來源。
SECRET_KEY:密鑰。
GLOBAL_PARAM:全域變數。
grantToUsers
List<GrantToUser>
授權使用者列表。請參見GrantToUser。
bpmsEnvironment
BpmsEnvironment
審批系統內容資訊。請參見BpmsEnvironment。
operates
List<String>
申請的權限類別型,包含以下類型:
SYNC_READ:資料來源同步讀。
SYNC_WRITE:資料來源同步寫。
SQL_QUERY:物理表及邏輯表的SQL查詢。
SQL_WRITE:物理表的SQL寫入。
SQL_ALTER:物理表的SQL修改。
SQL_DROP:物理表及邏輯表的SQL刪除。
SELECT:資料服務API的查詢。
WRITE:寫入許可權。
DEV:開發許可權。
USE:使用許可權。
UPDATE:改表資料。
PIPELINE_ENCRY:整合加密。
PIPELINE_DECRY:整合解密。
levels
List<String>
許可權等級,包含三個等級:HIGH、MIDDLE、LOW。
operations
List<String>
權限類別型,包含以下類型:
SELECT-查詢。
DESCRIBE-查表結構。
UPDATE-改表資料。
ALTER-改表結構。
DELETE-刪除表。
COPY_TASK-複製。
resources
List<BpmsResource>
資源內容,請參見BpmsResource。
applyObject
ApplyObject
申請對象資訊,請參見ApplyObject。
reason
String
申請原因。
GrantToUser
參數名稱
參數類型
描述
account
Account
授權賬戶列表,請參見Account。
period
Period
有效期間,請參見Period。
Account
參數名稱
參數類型
描述
accountType
String
授與類型,包括個人帳號、生產帳號和應用帳號三種。
PERSONAL:個人帳號。
PRODUCE:生產帳號。
APPLICATION:應用帳號。
userName
String
結束時間格式為yyyy-mm-dd。如:2022-09-11。
Period
參數名稱
參數類型
描述
periodType
String
有效期間類型支援長期(LONG_TERM)。
periodEnd
String
許可權到期時間格式為yyyy-mm-dd。如:2022-09-11。
BpmsEnvironment
參數名稱
參數類型
描述
projectName
String
專案名稱。
bizUnitName
String
業務板塊名稱。
resourceEnv
String
環境分為生產環境和開發環境兩種環境。
PROD:生產。
DEV:開發。
BpmsResource
參數名稱
參數類型
描述
resourceType
String
請參見審批訊息內容中繼資料描述。
resourceName
String
資源名稱。
children
List<Children>
欄位列表,請參見Children。
operations
List<String>
請參見審批訊息內容中繼資料描述的operates。
authTypes
String
申請權限類別型。
Children
參數名稱
參數類型
描述
resourceName
String
欄位名稱。
resourceProperties
String
欄位屬性。
ResourceProperties
參數名稱
參數類型
描述
columnType
String
欄位類型。
columnIsPartition
String
是否為分區欄位。
columnIsPk
String
是否為主鍵。
ApplyObject
參數名稱
參數類型
描述
objectName
String
對象名稱。
codeContent
String
代碼內容。
name
String
商務活動英文名稱。
bizObjectType
String
物件類型。
bizObjectChangeType
String
變更類型。
bizObjectPkField
String
組件欄位。
bizObjectParent
String
所屬父物件。
bizObjectChildren
String
下遊子物件。
bizProcessCn
String
活動名稱。
bizProcessType
String
活動類型。
bizProcessChangeType
String
變更類型。
bizProcessNodes
String
流程節點。
atomicIndexCn
String
指標名稱。
dataType
String
資料類型。
unit
String
計量單位。
bizProcess
String
活動名稱。
des
String
活動口徑。
derivedLogic
String
衍生公司。
protoLogics
String
計算邏輯。
返回參數
processInstanceId(String):第三方審批執行個體ID。如:6d1bxxxx。
撤銷審批
說明提交審批後,若申請內容不符合預期,可撤銷審批。
請求方式:POST。
請求地址:http(s)://{url}/dataphin/bpms/processinstance/revoke。
Query參數
參數名稱
參數類型
描述
accessToken
String
調用服務端API的憑證。
Dataphin頁面自動產生,或使用者產生填入Dataphin。如:6d1bxxxx。
timestamp
String
單位毫秒,資訊發送時間戳記。如:1654156836531。
Body參數
參數名稱
參數類型
描述
applyId
String
Dataphin審批單Id。如:1223。
processInstanceId
String
第三方審批執行個體Id。如:6d1bxxxx。
operatingUserId
String
操作人工號。如:6d1bxxxx。
返回參數
result(String):撤回結果資訊。僅當傳回值為success時被認定為成功。
查詢審批執行個體URL
請求方式:GET。
請求地址:http(s)://{url}/dataphin/bpms/processinstance/apply。
Query參數
參數名稱
參數類型
描述
accessToken
String
調用服務端API的憑證。
Dataphin頁面自動產生,或使用者產生填入Dataphin。如:6d1bxxxx。
timestamp
String
單位毫秒,資訊發送時間戳記。如:1654156836531。
回調介面
https://{callbackUrl}即為審批設定中其他配置的Callback URL。
accessToken:調用服務端API的憑證。Dataphin頁面自動產生,或使用者產生填入Dataphin。
callBackAesKey:回調認證憑證。Dataphin頁面自動產生,或使用者產生填入Dataphin。
回調方法
請求方式:POST。
請求地址:http://{callbackUrl}/api/oa/bpms/integration/thirdparty/callback。
Query參數
參數名稱
參數類型
描述
signature
String
訊息認證資訊,請參見加解密方法。
timestamp
String
單位毫秒,資訊發送時間戳記。如:1654156836531。
nonce
String
隨機數,請參見加解密方法。
Body參數
encrypt(String):加密資訊。如:ajls384k。
返回參數
encrypt(String):回調狀態加密資訊。如:ajls384k。
回調加密內容
回調連通性校正
傳入加密參數:
applyStatus(String):檢查連通性參數。如:CHECK。
返回加密參數:
success:成功回調傳回值。
回調返回bpms執行個體審批結果
傳入加密參數:
參數名稱
參數類型
描述
applyId
String
Dataphin審批單Id。如:1223。
processInstanceId
String
第三方審批執行個體Id。如:6d1bxxxx。
comment
String
審批執行個體評論資訊。
applyStatus
String
accept:接受。
reject:拒絕。
revoke:撤銷。
nodes
List<ApplyCallBackNode>
第三方審批系統側的審批節點列表,非必填,當對接方式選擇為顯示三方審批的所有節點時填入。
ApplyCallBackNode
參數名稱
參數類型
描述
nodeId
String
節點ID,從1到n進行排序。
nodeStatus
String
節點狀態(ApproveNodeStatusEnum)。
APPROVING:審批中。
ACCEPTED:已通過。
REJECTED:已駁回。
REVOKED:已撤回。
nodeName
String
節點名稱。
approverRelation
String
審批關係(ApproveOperatorEnum)。
AND:多人均要審批方可通過。
OR:任何一人審批通過即可。
pendingApprovers
List<ExternalApproverInfo>
當前待審批人列表,如果相關審批人已審批,則該欄位為空白。
records
List<OperationRecord>
當審批人員執行操作時填入,按照時間先後順序排序。
ExternalApproverInfo
參數名稱
參數類型
描述
userId
String
第三方審批系統側的使用者ID。如:1223。
userName
String
第三方審批系統側的使用者名稱。如:張三。
OperationRecord
參數名稱
參數類型
描述
operateUser
ExternalApproverInfo
操作人資訊。如:{"userId":"1111", "userName":"張三"}。
action
String
操作類型(ApproveNodeActionType)。
ASSIGN_APPROVE:轉交許可權申請。
COUNTER_SIGN_APPROVE:加簽許可權申請。
REVOKE_APPLY:撤回許可權申請。
APPROVE:審批許可權。
comment
String
操作評論。
operatedTime
String
操作時間。
transferApprovers
List<ExternalApproverInfo>
轉移目標人列表,非必填,當執行加簽或者轉交操作時填寫。如:[{"userId":"2222", "userName":"李四"}]。
返回加密參數
success:成功回調傳回值。
回調返回bpms執行個體審批結果範例
當前第三方審批系統支援僅顯示最終審批結果和顯示三方審批的所有節點兩種對接方式。不同對接方式下,第三方審批系統返回的審批資訊內容各不相同。
僅顯示最終審批結果
該對接方式僅需返回審批系統的最終結果,系統中僅展示開始節點和結束節點。僅當第三方審批系統側的整體審批次程序結束後,調用該回調介面即可。回傳內容結構體範例如下:
{ "applyId": "123456", "applyStatus": "accept", "comment": "同意審批", "processInstanceId": "qwqwqqq" }說明nodes欄位在該對接方式下無需填寫。
applyStatus欄位可填寫
accept、reject或revoke。approving表示審批中,為中間態,僅供顯示三方審批的所有節點對接方式下使用。
顯示三方審批的所有節點
該對接方式需返回審批系統每個節點的詳情,系統中將同步展示所有審批節點。當某一審批人員執行審批操作時,即可通過該回調介面將當前的審批節點語音總機至Dataphin系統。
涉及欄位的解釋說明
該對接方法下需要傳入
applyId、applyStatus、processInstanceId和nodes欄位。整體審批單狀態applyStatus,可選值:approving、accept、reject、revoke。
當存在某一審批節點流程尚未結束時,applyStatus設定為approving。
當所有審批節點均審批通過時,applyStatus設定為accept。
當存在某一審批節點被審批拒絕時,applyStatus設定為reject。
當存在某一審批節點被審批撤回時,applyStatus設定為revoke。
審批節點列表根據內部的nodeId進行排序,nodeId格式為1,2,3。
審批節點狀態nodeStatus,可選值:APPROVING、ACCEPTED、REJECTED和REVOKED。
如果當前審批節點流程未結束,nodeStatus設定為APPROVING。
如果當前審批節點審批通過,nodeStatus設定為ACCEPTED。
如果當前審批節點審批拒絕,nodeStatus設定為REJECTED。
如果當前審批節點審批撤回,nodeStatus設定為REVOKED。
審批節點展示名稱nodeName。
節點審批關係approverRelation,可選值:OR和AND。
OR:任一審批人審批處理即可通過。
AND:所有人審批處理方可通過。
待審批人列表pendingApprovers。
未執行審批處理的審批人列表。
當有相關人員執行審批操作時,下次傳輸時,需要從待審批列表中移除,然後寫入到操作記錄列表中。
操作記錄列表records。
執行操作的操作人資訊operateUser。
操作評論comment。
操作時間operatedTime,操作記錄列表按照操作時間升序排列。
操作類型action,可選值:ASSIGN_APPROVE、COUNTER_SIGN_APPROVE、REVOKE_APPLY、APPROVE。
當節點審批關係為OR,待審批人中某一審批人通過,action設定為APPROVE,同時審批節點狀態nodeStatus設定為ACCEPTED。
當節點審批關係為OR,待審批人中某一審批人拒絕,action設定為APPROVE,同時審批節點狀態nodeStatus設定為REJECTED。
當節點審批關係為OR,待審批人中某一審批人撤回,action設定為REVOKE_APPLY,同時審批節點狀態nodeStatus設定為REVOKED。
當待審批人中某一審批人執行轉交操作,action設定為ASSIGN_APPROVE,同時審批節點狀態nodeStatus設定為ACCEPTED。
當待審批人中某一審批人執行加簽操作,action設定為COUNTER_SIGN_APPROVE,同時審批節點狀態nodeStatus設定為ACCEPTED。
當節點審批關係為AND,某一審批人通過,action設定為APPROVE。如果剩餘人未執行審批,審批節點狀態仍為APPROVING;當所有人審批通過時,審批節點狀態nodeStatus設定為ACCEPTED。
當節點審批關係為AND,某一審批人拒絕,action設定為APPROVE,審批節點狀態nodeStatus設定為ACCEPTED。
當節點審批關係為AND,某一審批人撤回,action設定為REVOKE_APPLY,審批節點狀態nodeStatus設定為ACCEPTED。
轉移目標人列表transferApprovers,記錄被加簽或者轉交的人員資訊。
不同審批情境下審批內容的結構體
加解密方法
加密(以bpms接收回調為例):
Map<String, String> callBackJson = Maps.newHashMap(); callBackJson.put("applyId", "1"); callBackJson.put("applyStatus", "accept"); callBackJson.put("processInstanceId", "2"); callBackJson.put("comment", "test"); // 如果對接方式選擇 “顯示三方審批的所有節點”,需要填充 nodes 欄位資訊 String nodesJson = "[{"approverRelation":"OR","nodeId":"1","nodeName":"執行通過節點測試","nodeStatus":"ACCEPTED","pendingApprovers":[],"records":[{"action":"APPROVE","comment":"同意審批","operateUser":{"userId":"22222","userName":"張三"},"operatedTime":"2026-03-18 15:14:23"}]}]"; callBackJson.put("nodes", nodesJson) String callBackResult = JSON.toJSONString(callBackJson); ThirdPartyCrypto callbackCrypto = new ThirdPartyCrypto(token, aesKey); String timestamp = String.valueOf(System.currentTimeMillis()); String nonce = ThirdPartyCrypto.Utils.getRandomStr(16); String encrypt = callbackCrypto.encrypt(nonce, callBackResult); String signature = callbackCrypto.getSignature(token, timestamp, nonce, encrypt);解密(以bpms返回成功資訊為例):
String encryptMsg = JSONObject.parseObject(encrypt); String decryptMsg = callbackCrypto.getDecryptMsg(signature, timestamp, nonce, encryptMsg); if ("success".equalsIgnoreCase(decryptMsg)) { log.error("call back success"); }加解密工具
import com.alibaba.fastjson.JSON; import org.apache.commons.codec.binary.Base64; import javax.crypto.Cipher; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; import java.io.ByteArrayOutputStream; import java.lang.reflect.Field; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.security.MessageDigest; import java.security.Permission; import java.security.PermissionCollection; import java.security.Security; import java.util.Arrays; import java.util.HashMap; import java.util.Map; import java.util.Random; /** * Dataphin開放平台加解密方法 */ public class ThirdPartyCrypto { private static final Charset CHARSET = StandardCharsets.UTF_8; private static final Base64 BASE_64 = new Base64(); private final byte[] AES_KEY; private final String TOKEN; /** * ask getPaddingBytes key固定長度 **/ private static final Integer AES_ENCODE_KEY_LENGTH = 43; /** * 加密隨機字串位元組長度 **/ private static final Integer RANDOM_LENGTH = 16; /** * 建構函式 * * @param token 開發人員設定的token * @param encodingAesKey 開發人員設定的EncodingAESKey * * @throws ThirdPartyEncryptException 執行失敗,請查看該異常的錯誤碼和具體的錯誤資訊 */ public ThirdPartyCrypto(String token, String encodingAesKey) throws ThirdPartyEncryptException { if (null == encodingAesKey || encodingAesKey.length() != AES_ENCODE_KEY_LENGTH) { throw new ThirdPartyEncryptException(ThirdPartyEncryptException.AES_KEY_ILLEGAL); } this.TOKEN = token; AES_KEY = Base64.decodeBase64(encodingAesKey + "="); } public Map<String, String> getEncryptedMap(String plaintext) throws ThirdPartyEncryptException { return getEncryptedMap(plaintext, System.currentTimeMillis(), Utils.getRandomStr(16)); } /** * 將和Dataphin同步的訊息體加密,返回加密Map * * @param plaintext 傳遞的訊息體明文 * @param timeStamp 時間戳記 * @param nonce 隨機字串 * @return * @throws ThirdPartyEncryptException */ public Map<String, String> getEncryptedMap(String plaintext, Long timeStamp, String nonce) throws ThirdPartyEncryptException { if (null == plaintext) { throw new ThirdPartyEncryptException(ThirdPartyEncryptException.ENCRYPTION_PLAINTEXT_ILLEGAL); } if (null == timeStamp) { throw new ThirdPartyEncryptException(ThirdPartyEncryptException.ENCRYPTION_TIMESTAMP_ILLEGAL); } if (null == nonce) { throw new ThirdPartyEncryptException(ThirdPartyEncryptException.ENCRYPTION_NONCE_ILLEGAL); } // 加密 String encrypt = encrypt(Utils.getRandomStr(RANDOM_LENGTH), plaintext); String signature = getSignature(TOKEN, String.valueOf(timeStamp), nonce, encrypt); Map<String, String> resultMap = new HashMap<String, String>(); resultMap.put("msg_signature", signature); resultMap.put("encrypt", encrypt); resultMap.put("timeStamp", String.valueOf(timeStamp)); resultMap.put("nonce", nonce); return resultMap; } /** * 密文解密 * * @param msgSignature 簽名串 * @param timeStamp 時間戳記 * @param nonce 隨機串 * @param encryptMsg 密文 * @return 解密後的原文 * @throws ThirdPartyEncryptException */ public String getDecryptMsg(String msgSignature, String timeStamp, String nonce, String encryptMsg) throws ThirdPartyEncryptException { //校正簽名 String signature = getSignature(TOKEN, timeStamp, nonce, encryptMsg); if (!signature.equals(msgSignature)) { throw new ThirdPartyEncryptException(ThirdPartyEncryptException.COMPUTE_SIGNATURE_ERROR); } // 解密 return decrypt(encryptMsg); } /** * 對明文加密. * @param plaintext 需要加密的明文 * @return 加密後base64編碼的字串 */ public String encrypt(String random, String plaintext) throws ThirdPartyEncryptException { try { byte[] randomBytes = random.getBytes(CHARSET); byte[] plainTextBytes = plaintext.getBytes(CHARSET); byte[] lengthByte = Utils.int2Bytes(plainTextBytes.length); ByteArrayOutputStream byteStream = new ByteArrayOutputStream(); byteStream.write(randomBytes); byteStream.write(lengthByte); byteStream.write(plainTextBytes); byte[] padBytes = PKCS7Padding.getPaddingBytes(byteStream.size()); byteStream.write(padBytes); byte[] unencrypted = byteStream.toByteArray(); byteStream.close(); Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding"); SecretKeySpec keySpec = new SecretKeySpec(AES_KEY, "AES"); IvParameterSpec iv = new IvParameterSpec(AES_KEY, 0, 16); cipher.init(Cipher.ENCRYPT_MODE, keySpec, iv); byte[] encrypted = cipher.doFinal(unencrypted); String result = BASE_64.encodeToString(encrypted); return result; } catch (Exception e) { throw new ThirdPartyEncryptException(ThirdPartyEncryptException.COMPUTE_ENCRYPT_TEXT_ERROR); } } /** * 對密文進行解密. * @param text 需要解密的密文 * @return 解密得到的明文 */ private String decrypt(String text) throws ThirdPartyEncryptException { byte[] originalArr; try { // 設定解密模式為AES的CBC模式 Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding"); SecretKeySpec keySpec = new SecretKeySpec(AES_KEY, "AES"); IvParameterSpec iv = new IvParameterSpec(Arrays.copyOfRange(AES_KEY, 0, 16)); cipher.init(Cipher.DECRYPT_MODE, keySpec, iv); // 使用BASE64對密文進行解碼 byte[] encrypted = Base64.decodeBase64(text); // 解密 originalArr = cipher.doFinal(encrypted); } catch (Exception e) { throw new ThirdPartyEncryptException(ThirdPartyEncryptException.COMPUTE_DECRYPT_TEXT_ERROR); } String plainText; try { // 去除補位字元 byte[] bytes = PKCS7Padding.removePaddingBytes(originalArr); // 分離16位隨機字串,網路位元組序和corpId byte[] networkOrder = Arrays.copyOfRange(bytes, 16, 20); int plainTextLegth = Utils.bytes2int(networkOrder); plainText = new String(Arrays.copyOfRange(bytes, 20, 20 + plainTextLegth), CHARSET); } catch (Exception e) { throw new ThirdPartyEncryptException(ThirdPartyEncryptException.COMPUTE_DECRYPT_TEXT_LENGTH_ERROR); } return plainText; } /** * 數位簽章 * * @param token isv token * @param timestamp 時間戳記 * @param nonce 隨機串 * @param encrypt 加密文本 * @return * @throws ThirdPartyEncryptException */ public String getSignature(String token, String timestamp, String nonce, String encrypt) throws ThirdPartyEncryptException { try { String[] array = new String[] {token, timestamp, nonce, encrypt}; Arrays.sort(array); System.out.println(JSON.toJSONString(array)); StringBuffer sb = new StringBuffer(); for (int i = 0; i < 4; i++) { sb.append(array[i]); } String str = sb.toString(); System.out.println(str); MessageDigest md = MessageDigest.getInstance("SHA-1"); md.update(str.getBytes()); byte[] digest = md.digest(); StringBuffer hexstr = new StringBuffer(); String shaHex = ""; for (int i = 0; i < digest.length; i++) { shaHex = Integer.toHexString(digest[i] & 0xFF); if (shaHex.length() < 2) { hexstr.append(0); } hexstr.append(shaHex); } return hexstr.toString(); } catch (Exception e) { throw new ThirdPartyEncryptException(ThirdPartyEncryptException.COMPUTE_SIGNATURE_ERROR); } } public static class Utils { public Utils() { } public static String getRandomStr(int count) { String base = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; Random random = new Random(); StringBuffer sb = new StringBuffer(); for (int i = 0; i < count; ++i) { int number = random.nextInt(base.length()); sb.append(base.charAt(number)); } return sb.toString(); } public static byte[] int2Bytes(int count) { byte[] byteArr = new byte[] {(byte)(count >> 24 & 255), (byte)(count >> 16 & 255), (byte)(count >> 8 & 255), (byte)(count & 255)}; return byteArr; } public static int bytes2int(byte[] byteArr) { int count = 0; for (int i = 0; i < 4; ++i) { count <<= 8; count |= byteArr[i] & 255; } return count; } } public static class PKCS7Padding { private static final Charset CHARSET = StandardCharsets.UTF_8; private static final int BLOCK_SIZE = 32; public PKCS7Padding() { } public static byte[] getPaddingBytes(int count) { int amountToPad = 32 - count % 32; if (amountToPad == 0) { amountToPad = 32; } char padChr = chr(amountToPad); String tmp = new String(); for (int index = 0; index < amountToPad; ++index) { tmp = tmp + padChr; } return tmp.getBytes(CHARSET); } public static byte[] removePaddingBytes(byte[] decrypted) { int pad = decrypted[decrypted.length - 1]; if (pad < 1 || pad > 32) { pad = 0; } return Arrays.copyOfRange(decrypted, 0, decrypted.length - pad); } private static char chr(int a) { byte target = (byte)(a & 255); return (char)target; } } public static class ThirdPartyEncryptException extends Exception { public static final int SUCCESS = 0; public static final int ENCRYPTION_PLAINTEXT_ILLEGAL = 900001; public static final int ENCRYPTION_TIMESTAMP_ILLEGAL = 900002; public static final int ENCRYPTION_NONCE_ILLEGAL = 900003; public static final int AES_KEY_ILLEGAL = 900004; public static final int SIGNATURE_NOT_MATCH = 900005; public static final int COMPUTE_SIGNATURE_ERROR = 900006; public static final int COMPUTE_ENCRYPT_TEXT_ERROR = 900007; public static final int COMPUTE_DECRYPT_TEXT_ERROR = 900008; public static final int COMPUTE_DECRYPT_TEXT_LENGTH_ERROR = 900009; public static final int COMPUTE_DECRYPT_TEXT_CORPID_ERROR = 900010; private static Map<Integer, String> msgMap = new HashMap(); private Integer code; static { msgMap.put(0, "成功"); msgMap.put(900001, "加密明文文本非法"); msgMap.put(900002, "加密時間戳記參數非法"); msgMap.put(900003, "加密隨機字串參數非法"); msgMap.put(900005, "簽名不匹配"); msgMap.put(900006, "簽名計算失敗"); msgMap.put(900004, "不合法的aes key"); msgMap.put(900007, "計算加密文字錯誤"); msgMap.put(900008, "計算解密文字錯誤"); msgMap.put(900009, "計算解密文字長度不匹配"); msgMap.put(900010, "計算解密文字corpid不匹配"); } public Integer getCode() { return this.code; } public ThirdPartyEncryptException(Integer exceptionCode) { super((String)msgMap.get(exceptionCode)); this.code = exceptionCode; } } static { try { Security.setProperty("crypto.policy", "limited"); RemoveCryptographyRestrictions(); } catch (Exception var1) { } } private static void RemoveCryptographyRestrictions() throws Exception { Class<?> jceSecurity = getClazz("javax.crypto.JceSecurity"); Class<?> cryptoPermissions = getClazz("javax.crypto.CryptoPermissions"); Class<?> cryptoAllPermission = getClazz("javax.crypto.CryptoAllPermission"); if (jceSecurity != null) { setFinalStaticValue(jceSecurity, "isRestricted", false); PermissionCollection defaultPolicy = (PermissionCollection)getFieldValue(jceSecurity, "defaultPolicy", (Object)null, PermissionCollection.class); if (cryptoPermissions != null) { Map<?, ?> map = (Map)getFieldValue(cryptoPermissions, "perms", defaultPolicy, Map.class); map.clear(); } if (cryptoAllPermission != null) { Permission permission = (Permission)getFieldValue(cryptoAllPermission, "INSTANCE", (Object)null, Permission.class); defaultPolicy.add(permission); } } } private static Class<?> getClazz(String className) { Class clazz = null; try { clazz = Class.forName(className); } catch (Exception var3) { } return clazz; } private static void setFinalStaticValue(Class<?> srcClazz, String fieldName, Object newValue) throws Exception { Field field = srcClazz.getDeclaredField(fieldName); field.setAccessible(true); Field modifiersField = Field.class.getDeclaredField("modifiers"); modifiersField.setAccessible(true); modifiersField.setInt(field, field.getModifiers() & -17); field.set((Object)null, newValue); } private static <T> T getFieldValue(Class<?> srcClazz, String fieldName, Object owner, Class<T> dstClazz) throws Exception { Field field = srcClazz.getDeclaredField(fieldName); field.setAccessible(true); return dstClazz.cast(field.get(owner)); } }