1.问题介绍前端angularjs后端springcloud登录时前端页面对password通过RSA加密后传入后端API接口后端对RSA进行解密......通过系统页面登录一切正常但是通过postman调用登录接口会报错。下面是用Postman测试接口- DUBBO - 服务响应: Client[consumer],InterfaceName[SharetekRemoteClientService],MethodName[queryByUserName],SpendTime[23ms] 解密前1G7BzsJn6LiCvXifIwW9KchNZq2u98dws9jLTCrkhjfLzXzmYRGaQr1lpYC1Y41TeBQ4hBJZ2/1NPYu9FMrXDoYaOslNo0seCM9Ytg3XNxmvQZ6KDzxQxsDUorm4GPI1FvhI/tSOz9eSdohaWoQXzNkD4zUxX/8mKmqTt5NZUZY 2024-07-03 18:43:12 [XNIO-1 task-2] INFO c.s.c.log.event.LogEventListener - [127.0.0.1]内网IP[admin][Success][登录成功] 2024-07-03 18:43:12 [XNIO-1 task-2] INFO c.s.c.d.filter.DubboRequestFilter - DUBBO - 服务调用: Client[consumer],InterfaceName[RemoteLogService],MethodName[saveLogininfor] 2024-07-03 18:43:12 [XNIO-1 task-2] INFO c.s.c.d.filter.DubboRequestFilter - DUBBO - 服务响应: Client[consumer],InterfaceName[RemoteLogService],MethodName[saveLogininfor],SpendTime[2ms] 2024-07-03 18:43:12 [XNIO-1 task-2] INFO c.s.auth.listener.UserActionListener - user doLogin, useId:PC:1805808875250122752, token:eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJsb2dpblR5cGUiOiJsb2dpbiIsImxvZ2luSWQiOiJQQzoxODA1ODA4ODc1MjUwMTIyNzUyIiwicm5TdHIiOiIyREhHcmx4NFhoa0g3eDJ5b2Z3ZWJNVkNpbllvYTZkWCIsInVzZXJJZCI6MTgwNTgwODg3NTI1MDEyMjc1MiwidXNlck5hbWUiOiJhZG1pbiIsImRlcHRJZCI6MSwiZGVwdE5hbWUiOiIiLCJkZXB0Q2F0ZWdvcnkiOiIifQ.ttv1dLxjSKPY8SO9JpyKsSl_jGyPva-yXQXc40pfd9Y 2024-07-03 18:43:12 [XNIO-1 task-2] INFO c.s.auth.listener.UserActionListener - user doLogout, useId:PC:1805808875250122752, token:eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJsb2dpblR5cGUiOiJsb2dpbiIsImxvZ2luSWQiOiJQQzoxODA1ODA4ODc1MjUwMTIyNzUyIiwicm5TdHIiOiJINEE3b2FUQ1BmWFFUZzB0UTI5M1l5c3I2U1JmUlp2cCIsInVzZXJJZCI6MTgwNTgwODg3NTI1MDEyMjc1MiwidXNlck5hbWUiOiJhZG1pbiIsImRlcHRJZCI6MSwiZGVwdE5hbWUiOiIiLCJkZXB0Q2F0ZWdvcnkiOiIifQ.BLGAMhsQvDza7AHGk1q2j7acF6UWg8n6psQp2rQNgp0 2024-07-03 18:43:17 [timeoutChecker_1_1] ERROR i.s.c.r.n.NettyClientChannelManager - no available service endpoint found in cluster default, please make sure registry config correct and keep your seata-server is running 2024-07-03 18:43:18 [timeoutChecker_2_1] ERROR i.s.c.r.n.NettyClientChannelManager - no available service endpoint found in cluster default, please make sure registry config correct and keep your seata-server is running 2024-07-03 18:43:27 [timeoutChecker_1_1] ERROR i.s.c.r.n.NettyClientChannelManager - no available service endpoint found in cluster default, please make sure registry config correct and keep your seata-server is running 2024-07-03 18:43:28 [timeoutChecker_2_1] ERROR i.s.c.r.n.NettyClientChannelManager - no available service endpoint found in cluster default, please make sure registry config correct and keep your seata-server is running 2024-07-03 18:43:37 [timeoutChecker_1_1] ERROR i.s.c.r.n.NettyClientChannelManager - no available service endpoint found in cluster default, please make sure registry config correct and keep your seata-server is running 2024-07-03 18:43:38 [timeoutChecker_2_1] ERROR i.s.c.r.n.NettyClientChannelManager - no available service endpoint found in cluster default, please make sure registry config correct and keep your seata-server is running 2024-07-03 18:43:40 [XNIO-1 task-2] INFO c.s.c.d.filter.DubboRequestFilter - DUBBO - 服务调用: Client[consumer],InterfaceName[SharetekRemoteClientService],MethodName[queryByUserName] 2024-07-03 18:43:40 [XNIO-1 task-2] INFO c.s.c.d.filter.DubboRequestFilter - DUBBO - 服务响应: Client[consumer],InterfaceName[SharetekRemoteClientService],MethodName[queryByUserName],SpendTime[29ms] 2024-07-03 18:43:40 [XNIO-1 task-2] INFO c.s.c.d.filter.DubboRequestFilter - DUBBO - 服务调用: Client[consumer],InterfaceName[SharetekRemoteClientService],MethodName[queryByUserName] 2024-07-03 18:43:40 [XNIO-1 task-2] INFO c.s.c.d.filter.DubboRequestFilter - DUBBO - 服务响应: Client[consumer],InterfaceName[SharetekRemoteClientService],MethodName[queryByUserName],SpendTime[30ms] 解密前1G7BzsJn6LiCvXifIwW9KchNZq2u98dws9jLTCrkhjfLzXzmYRGaQr1lpYC1Y41TeBQ4h BJZ2/1NPYu9FMrXDoYaOslNo0seCM9Ytg3XNxmvQZ6KDzxQxsDUorm4GPI1FvhI/tSOz9eSdohaWoQXzNkD4zUxX/8mKmqTt5NZUZY 2024-07-03 18:43:40 [XNIO-1 task-2] ERROR c.s.c.w.h.GlobalExceptionHandler - 请求地址/api/token,发生未知异常. cn.hutool.crypto.CryptoException: BadBlockException: unable to decrypt block at cn.hutool.crypto.asymmetric.AsymmetricCrypto.decrypt(AsymmetricCrypto.java:277) at cn.hutool.crypto.asymmetric.RSA.decrypt(RSA.java:174) at cn.hutool.crypto.asymmetric.AsymmetricDecryptor.decrypt(AsymmetricDecryptor.java:58) at cn.hutool.crypto.asymmetric.AsymmetricDecryptor.decryptStr(AsymmetricDecryptor.java:71) at cn.hutool.crypto.asymmetric.AsymmetricDecryptor.decryptStr(AsymmetricDecryptor.java:83) at com.sharetek.auth.utils.RSAUtils.decrypt(RSAUtils.java:77) at com.sharetek.auth.service.impl.SharetekPasswordAuthStrategy.sharetekLogin(SharetekPasswordAuthStrategy.java:122) at com.sharetek.auth.service.ISharetekAuthStrategy.login(ISharetekAuthStrategy.java:32) at com.sharetek.auth.controller.SharetekTokenController.login(SharetekTokenController.java:99) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.base/java.lang.reflect.Method.invoke(Method.java:568) at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:255) at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:188) at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:118) at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:926) at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:831) at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)密文对比如下//正确解密前1G7BzsJn6LiCvXifIwW9KchNZq2u98dws9jLTCrkhjfLzXzmYRGaQr1lpYC1Y41TeBQ4hBJZ2/1NPYu9FMrXDoYaOslNo0seCM9Ytg3XNxmvQZ6KDzxQxsDUorm4GPI1FvhI/tSOz9eSdohaWoQXzNkD4zUxX/8mKmqTt5NZUZY //postman解密前1G7BzsJn6LiCvXifIwW9KchNZq2u98dws9jLTCrkhjfLzXzmYRGaQr1lpYC1Y41TeBQ4h BJZ2/1NPYu9FMrXDoYaOslNo0seCM9Ytg3XNxmvQZ6KDzxQxsDUorm4GPI1FvhI/tSOz9eSdohaWoQXzNkD4zUxX/8mKmqTt5NZUZY2.解决方法对rsa密文里的所有空格用替换即可。3.RSA加解密在前端用js进行rsa加密和在java端用hutool进行rsa加密秘钥相同的前提下生成的密文格式不同java生成的密文更长但是在服务端用hutool解密后的结果是一样的前端js的密文用hutool包也可以完成解密。// js端对Sharetek加密rsa后的密文 G7BzsJn6LiCvXifIwW9KchNZq2u98dws9jLTCrkhjfLzXzmYRGaQr1lpYC1Y41TeBQ4hBJZ2/1NPYu9FMrXDoYaOslNo0seCM9Ytg3XNxmvQZ6KDzxQxsDUorm4GPI1FvhI/tSOz9eSdohaWoQXzNkD4zUxX/8mKmqTt5NZUZY // 用hutool包进行SRA加密后0d4109384740aa7508e47ec58a6a1870027b5cb4ae68de1343f49e6d2a1d8becfc6da7a3f3521323597522f54f896ffd271e458e406be0317532649becc5b88de9827c6c56ca2ba8f6a167cd889f8160a3f12473b4ff91c93b85d8dd61fad646c1394cc4d4e78db07776c4d445b704ac09d6958980ab3da37ab54bfeda6ded864.hutool包RSA加解密工具类dependency groupIdcn.hutool/groupId artifactIdhutool-crypto/artifactId version5.8.27/version /dependencypackage com.sharetek.auth.utils; import cn.hutool.core.io.file.FileReader; import cn.hutool.crypto.asymmetric.KeyType; import cn.hutool.crypto.asymmetric.RSA; /** * author tianjunmou * title RSAUtils * date 2024/6/25 14:50 * description RSA加解密工具类 */ public class RSAUtils { // 在classpath下的公私钥文件 // 文本格式的私钥内容(不包含-----BEGIN PRIVATE KEY-----,-----END PRIVATE KEY-----) private static String pubKeyFilePathInClasspath keys/public_key.pem; private static String priKeyFilePathInClasspath keys/private_key.pem; public static void main(String[] args) throws Exception { // 要加密的文本 String text Sharetek; System.out.println(原始密码 text); long startTime System.currentTimeMillis(); // 获取公钥并进行rsa加密 String encryptedString encrypt(text, getPublicKey(pubKeyFilePathInClasspath)); System.out.println(SRA加密后 encryptedString); // 获取私钥并进行rsa解密 // encryptedString Kz72esN2/Ndx5wUmYPT9ntCFsbzrHCB1qKZu0AlCGDkLfmsnpW4b6wxTiDEIQ9KAHRGkHgwi0DpgibmU5mxjsVQEp1dvzvLyZPHPLNitmjSf3F9149lLLqQRfrh5CrJdqRQb2mcUcA7NwVDa28qebdpkH8kahrVTPW2cZZQ; // encryptedString i4Q01UvbWIA0M2kS4iWFd0Bh6th/bDSS0I/tQ2xGG/MEFLJY3KgQgx5UBI5xKHA05/7oAPf7X2EM5t/k7/nIOkafMX6QZTy6kSkcyipO1Nc8s68FLVYUWQWWD9uPm5xYAYTlh43aAfolEoow5XeeoMIih7mIJomq5SQ0CoTK2Q; encryptedString Fwoz75HNOffQfwgRkNt7IUJZoEuLrCI5gSZjpAx4npo2fe0gH6nlAOhi6r3YwH7tC8mqgp1GP0mvujATpQEz4ZlaZfkm/f8P0sqJTj6dBCPu2ph3Wcg1SvXI0TGeDsiiyeTrzNM2cww53AeTpJS332bi39vso3p8iMA0aQL0; String decryptedString decrypt(encryptedString); System.out.println(耗时: (System.currentTimeMillis() - startTime) ms); System.out.println(解密后 decryptedString); } /** * 使用公钥加密 * * param text 待使用rsa加密的明文 * param publicKey 文本格式的公钥内容(不包含-----BEGIN PUBLIC KEY-----,-----END PUBLIC KEY-----) * return */ private static String encrypt(String text, String publicKey) { return new RSA(null, publicKey).encryptHex(text, KeyType.PublicKey); } /** * 使用私钥解密 * * param encryptedString 使用rsa加密的密文串 * return */ public static String decrypt(String encryptedString) { System.out.println(解密前1 encryptedString); encryptedString encryptedString.replaceAll( , ); System.out.println(解密前2 encryptedString); String privateKey null; String publickKey null; try { privateKey getPrivateKey(priKeyFilePathInClasspath); publickKey getPublicKey(pubKeyFilePathInClasspath); } catch (Exception e) { throw new RuntimeException(e); } return new RSA(privateKey, null).decryptStr(encryptedString, KeyType.PrivateKey); } /** * 从公钥文件中读取公钥数据 * * param pubKeyFilePathInClasspath classpath下的公钥文件路径 * return * throws Exception */ private static String getPublicKey(String pubKeyFilePathInClasspath) throws Exception { return new FileReader(getAbsolutePath(pubKeyFilePathInClasspath)).readString(); } /** * 从私钥文件中读取私钥数据 * * param priKeyFilePathInClasspath classpath下的私钥文件路径 * return * throws Exception */ private static String getPrivateKey(String priKeyFilePathInClasspath) throws Exception { return new FileReader(getAbsolutePath(priKeyFilePathInClasspath)).readString(); } /** * 获取classpath下指定文件的绝对路径 * * param filePathInClasspath classpath下文件路径 * return */ private static String getAbsolutePath(String filePathInClasspath) { return ClassLoader.getSystemClassLoader() .getResource(filePathInClasspath).getPath(); } }参考资料Hutool参考文档HutoolJava工具集https://hutool.cn/docs/#/crypto/%E9%9D%9E%E5%AF%B9%E7%A7%B0%E5%8A%A0%E5%AF%86-AsymmetricCrypto