Salesforce REST api 使用 reactor With Spring WebClient

Salesforce REST api using reactor With Spring WebClient

我尝试从 Spring 引导网络客户端连接 Salesforce。我有带有以下代码的 JWT 令牌

String header = "{\"alg\":\"RS256\"}";
String claimTemplate = "'{'\"iss\": \"{0}\", \"sub\": \"{1}\", \"aud\": \"{2}\", \"exp\": \"{3}\", \"jti\": \"{4\"'}'";

try {
  StringBuffer token = new StringBuffer();

  //Encode the JWT Header and add it to our string to sign
  token.append(Base64.encodeBase64URLSafeString(header.getBytes("UTF-8")));

  //Separate with a period
  token.append(".");

  //Create the JWT Claims Object
  String[] claimArray = new String[4];
  claimArray[0] = "3MVG99OxTyEMCQ3gNp2PjkqeZKxnmAiG1xV4oHh9AKL_rSK.BoSVPGZHQukXnVjzRgSuQqGn75NL7yfkQcyy7";
  claimArray[1] = "my@email.com";
  claimArray[2] = "https://login.salesforce.com";
  claimArray[3] = Long.toString( ( System.currentTimeMillis()/1000 ) + 300);
  claimArray[4]=<JTI>
  MessageFormat claims;
  claims = new MessageFormat(claimTemplate);
  String payload = claims.format(claimArray);
  token.append(Base64.encodeBase64URLSafeString(payload.getBytes("UTF-8")));

  KeyStore keystore = KeyStore.getInstance("JKS");
  keystore.load(new FileInputStream("./path/to/keystore.jks"), "keystorepassword".toCharArray());
  PrivateKey privateKey = (PrivateKey) keystore.getKey("certalias", "privatekeypassword".toCharArray());

  Signature signature = Signature.getInstance("SHA256withRSA");
  signature.initSign(privateKey);
  signature.update(token.toString().getBytes("UTF-8"));
  String signedPayload = Base64.encodeBase64URLSafeString(signature.sign());
  token.append(".");
  token.append(signedPayload);


    System.out.println(token.toString());
} catch (Exception e) {
        e.printStackTrace();
    }

根据下面提到的 Salesforce 网站。我的类路径中有私钥 .der 文件。

我已经通过以下代码获得了 AuthToken。

    HttpClient client = HttpClient.create();
    ReactorClientHttpConnector conn = new ReactorClientHttpConnector(client);
WebClient web = WebClient.builder()
        .baseUrl("https://dev.salesforce.com")
        .defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_FORM_URLENCODED_VALUE)
        .clientConnector(conn).build();

Mono<Token> token = web.post()
            .uri("/services/oauth2/token")
            .body(BodyInserters.fromFormData("grant_type", "jwt-bearer")
            .with("assertion", getAuth()).exchange().flatMap(res->res.bodyToMono(Token.class));
return token;

但我收到 reactor.core.Exceptions$Reactiveexception io.netty.channel.AbstractChannel$AnnotatedConnectionException: connection timedout exception with no further information 异常。

请告诉我在 post Auth Token 创建方法中缺少什么。

如果您在 SF 设置中查看您的用户,底部是登录历史记录。它显示任何错误吗?它是否甚至登录正常并且“只是”在实际 API 调用时死机?

在 JWT 流程中,您不应该将整个令牌作为授权发送给 SF header。您将从令牌开始,SF 会向您发送一条消息,从该消息在后续调用中使用“access_token”... https://help.salesforce.com/articleView?id=remoteaccess_oauth_jwt_flow.htm&language=en_us 甚至有 Java 个样本。