使用 Workday 凭据发出 Adaptive Planning API 请求
本文中的部分链接指向 Workday Community。如果您没有 Workday Community 账户,请申请账户。
与 Workday 同步的用户,这些用户登录到 Workday 并使用
Adaptive Planning
可以运行的 Worklet Adaptive Planning
公共 API用户必须创建专门用于发出这些 API 请求的 ISU。这些用户必须在 credentials
元素 Adaptive Planning
API 请求,而不是用户名和密码。您可以缓存此令牌,并在其过期前继续使用。令牌过期后,您必须获取新的令牌。
先决条件
先决条件
Workday 域和安全组
- 确认需要 API 访问权限的 ISU 用户是否属于“Set Up: Adaptive Planning API Access”安全域。
Workday 设置任务
- 验证是否已在“User Sign-on”选项卡中启用“Single Sign-On”任务。Adaptive Planning选项卡
- 确认已在“Public API”选项卡中启用“Public APIsetup”任务。Adaptive Planning选项卡
- 验证集成系统用户 (ISU) 设置任务是否创建了专门用于发出 Workday Adaptive Planning API 请求的 ISU,并将其映射到Adaptive Planning用户帐户
Adaptive Planning
用户管理- 确认您是否看到开头为PublicAPIISU_位于“管理”>“用户”的用户列表中。
- 确认此用户是否具有其要运行的 API 所需的层级访问权限。默认情况下,新的集成系统用户不会获得层级访问权限。
步骤
步骤
- 获取证书并提取公钥。
- 使用该证书在 Workday 中注册 API 客户端。
- 生成 JWT 令牌,检索 Workday access_token,然后检索 AdaptiveAPIAccessToken。
- 在中使用 AdaptiveAPIAccessTokenAdaptive PlanningAPI Request
获取证书并提取公钥
您可以自行创建证书,也可以从知名证书颁发机构购买证书。有关 Workday 中的 X.509 证书所需参数的详细信息,请参见 概念:Workday 中的 X.509 证书。
- 从您的证书中提取公钥,以便上传到 Workday。
- 请保留您的私钥,以便在调用应用程序中使用。
- 注册 JWT 不记名令牌时,请将证书粘贴到 Workday 中。在脚本中引用您的私钥。
请参见 使用 JWT(JSON Web 令牌)的 OAuth 和 访问外部端点。
注册 Workday API 客户端
- 在 Workday 中注册客户端授权类型为“Jwt Bearer Grant”的 API 客户端。有关更多信息,请参见 注册 API 客户端 。
- 在 Workday 的“注册 API 客户端”页面中,将为您的证书派生的公钥复制到x.509 证书中。
- 对于“Scope (Functional Area)”,选择。Adaptive Planning
- 完成 API 客户端注册后,请将页面底部的字段复制到文本文件中以供稍后使用。
- Workday REST API 端点
- 令牌端点
- 授权端点
生成 JWT 令牌、检索 Workday access_token 和检索 AdaptiveAPIAccessToken
- 使用您的私钥,并通过运行下列伪代码生成 JWT 令牌。
- 要检索 Workday 访问令牌,请创建POST向令牌端点发送请求,传递grant_type和assertion。使用在 Workday 中注册 API 客户端后复制的令牌端点。令牌端点示例:https://{host or gateway}/ccx/oauth2/{tenant}/token示例CURL向令牌端点发出请求curl --request POST 'https://{host or gateway}/ccx/oauth2/{tenant}/token' \ --header 'Content-Type: application/x-www-form-urlencoded' \ --data-urlencode 'grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer' \ --data-urlencode 'assertion={{the jwt assertion from your certificate}}'
- 使用 Workday 访问令牌调用 Workday 端点,以检索 AdaptiveAPIAccessToken。使用先前的access_tokenvalue 作为 Bearer 令牌Auth此字段的标头GET.访问令牌示例:https://{host or gateway}/ccx/api/planning/v1/{tenant}/adaptiveAPIAccessToken示例CURL请求 AdaptiveAPIAccessToken:curl --request GET 'https://{host or gateway}/ccx/api/planning/v1/{tenant}/adaptiveAPIAccessToken' \ --header 'Authorization: Bearer {{the prior access_token value}}' \ --data-raw ''
- 调用Adaptive Planning在 HTTP 请求的 XML 文件的凭据元素中使用 AdaptiveAPIAccessToken 的 APIPOST。示例:curl -H "Content-Type: text/xml" -d '<?xml version='1.0' encoding='UTF-8'?><call method="exportLevels" callerName="a string that identifies your client application"><credentials token="ID eyJhbDci0iJSUzUxMiIsUmtpZCI6IdvcmtkYXlfa2V5In0.eyJpc3KiOiJXb3JrZGFZIiwiYXV0aF90aW1lIjoxNTczMTY3NjU2LBjzeXnfynnJd.bztQzBmHeTj1amnHA-r96TdrJK0MXMghUFF1KyjxqIq6ruHU63dJp3JAJn3Eche7SEcoZBVGX4wJgna106pmCqgrrVWMf13Hg_sb_szabal2XN1KEEk1qh8z1IDlbt6qJIL_xyW3J2nNSs5ima3vJUYU5sRQXwXst0GuFWXpy464GyB4oKcscrg28X3dnPO_ytdohMKHsWkqyHQKXFQwoQezFaGy10sp4RRUj0lpOZX8C9oBHDYA58IXxGkqKLJVNPvDND6rGY5fTHQ-yxpe1nz-WqB0boiq9a-dv8b3EBzbelxj2fCPdMbng6kzygDcA2at_7BNQiyzfIovS5AG"/><include versionID="3" inaccessibleValues="false"/><sheet id="3" /></call>' -X POST https://api.adaptiveplanning.com/api/v23
用于生成 JWT 令牌的 Java 应用程序示例
此示例 Java 应用程序会生成 JWT 令牌。
//********************************************************************** // // File: TestPublicAPISample.java // // Copyright 2004-2019 Workday Adaptive Planning. // All Rights Reserved. // // This work contains trade secrets and confidential material of // Workday Adaptive Planning and its use or disclosure in whole or in part // without the express written permission of Workday Adaptive Planning is prohibited. // //********************************************************************** import java.io.FileInputStream; import java.security.KeyStore; import java.security.PrivateKey; import java.security.Signature; import java.text.MessageFormat; //import java.util.Base64; import org.apache.commons.codec.binary.Base64; public class AccessAdaptiveAPI { public static void main(String args[]) { String jwtKeyStoreFileString = "/Library/Java/JavaVirtualMachines/jdk1.8.0_172.jdk/Contents/Home/jre/lib/security/JWTkeystore.jks"; String clientIDString = "BlywNDM1NmMtZTk2Mi00NTZiTWEyZjktZWM1NGJiOGQ3Yjca"; String userIdString = "PublicAPIISU_Test"; System.out.println(GetAccessToken(clientIDString,userIdString,jwtKeyStoreFileString)); } public void callAPI() { } public String getAdaptiveAPIToken() { return ""; } public String getJWTToken(String privateKey, String username) { return ""; } public void callWorkdayAPI() { } public static String GetAccessToken(String clientId, String userId, String jwtKeyStore) { String header = "{\"alg\":\"RS256\",\"typ\":\"JWT\"}"; String claimTemplate = "'{'\"iss\": \"{0}\", \"sub\": \"{1}\", \"aud\": \"{2}\", \"exp\": \"{3}\"'}'"; 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]; //iss claimArray[0] = clientId; //sub claimArray[1] = userId; //aud claimArray[2] = "wd"; //exp claimArray[3] = Long.toString( ( System.currentTimeMillis()/1000 ) + 300); MessageFormat claims; claims = new MessageFormat(claimTemplate); String payload = claims.format(claimArray); //Add the encoded claims object token.append(Base64.encodeBase64URLSafeString(payload.getBytes("UTF-8"))); //token.append(Base64.encodeBase64URLSafeString(payload.getBytes("UTF-8"))); //Load the private key from a keystore KeyStore keystore = KeyStore.getInstance("JKS"); keystore.load(new FileInputStream(jwtKeyStore), "Workday123!".toCharArray()); PrivateKey privateKey = (PrivateKey) keystore.getKey("Workday", "Workday123!".toCharArray()); //Sign the JWT Header + "." + JWT Claims Object Signature signature = Signature.getInstance("SHA256withRSA"); signature.initSign(privateKey); signature.update(token.toString().getBytes("UTF-8")); String signedPayload = Base64.encodeBase64URLSafeString(signature.sign()); //Separate with a period token.append("."); //Add the encoded signature token.append(signedPayload); return token.toString(); //System.out.println(token.toString()); } catch (Exception e) { e.printStackTrace(); } return ""; } }
用于生成 JWT 令牌的 C# 应用程序示例
此示例 C# 应用程序会生成一个 JWT 令牌,该令牌会替换凭据元素中的用户名和密码。
Adaptive Planning
API 请求此示例代码需要 NuGet 页面。所需的 NuGet 包:
System.IdentityModel.Tokens.Jwt
var clientId = "BlywNDM1NmMtZTk2Mi00NTZiTWEyZjktZWM1NGJiOGQ3Yjca";//Client ID from workday API Client var isu = "PublicAPIISU_Test"; //the ISU var timeout = (DateTimeOffset.UtcNow.ToUnixTimeMilliseconds() / 1000 + 300).ToString(CultureInfo.InvariantCulture); var environment = "wd"; var pfxFilePath = @"C:\temp\JWTkeystore2.pfx"; var pfxPassword = "Workday123!"; var payload = new JwtPayload { {"iss", clientId}, {"sub", isu}, {"aud", environment}, {"exp", timeout }, }; var signingCredentials = new X509SigningCredentials(new X509Certificate2(pfxFilePath, pfxPassword), SecurityAlgorithms.RsaSha256); // the matching PKCS #12 file with private key var jwtHeader = new JwtHeader(signingCredentials); var secToken = new JwtSecurityToken(jwtHeader, payload); var handler = new JwtSecurityTokenHandler(); var tokenToWorkday = handler.WriteToken(secToken); Console.WriteLine(tokenToWorkday);
在中使用 AdaptiveAPIAccessToken Adaptive PlanningAPI 请求
Adaptive Planning
API 请求将 Workday 设置为
Adaptive Planning
公共 API 访问权限,的凭据元素 Adaptive Planning
API 请求使用 AdaptiveAPIAccessToken,而不是用户名和密码。使用用户名和密码的基本身份验证将不起作用。如需了解更多信息,请参见 Adaptive Planning REST API 和 API 方法 。示例 AdaptiveAPIAccessToken Adaptive PlanningAPI 请求
Adaptive Planning
API 请求<?xml version='1.0' encoding='UTF-8'?> <call method="exportLevels" callerName="a string that identifies your client application"> <credentials token="ID eyJhbDci0iJSUzUxMiIsUmtpZCI6IdvcmtkYXlfa2V5In0.eyJpc3KiOiJXb3JrZGFZIiwiYXV0aF90aW1lIjoxNTczMTY3NjU2LBjzeXnfynnJd.bztQzBmHeTj1amnHA-r96TdrJK0MXMghUFF1KyjxqIq6ruHU63dJp3JAJn3Eche7SEcoZBVGX4wJgna106pmCqgrrVWMf13Hg_sb_szabal2XN1KEEk1qh8z1IDlbt6qJIL_xyW3J2nNSs5ima3vJUYU5sRQXwXst0GuFWXpy464GyB4oKcscrg28X3dnPO_ytdohMKHsWkqyHQKXFQwoQezFaGy10sp4RRUj0lpOZX8C9oBHDYA58IXxGkqKLJVNPvDND6rGY5fTHQ-yxpe1nz-WqB0boiq9a-dv8b3EBzbelxj2fCPdMbng6kzygDcA2at_7BNQiyzfIovS5AG"/> <include versionID="3" inaccessibleValues="false"/> <sheet id="3" /> </call>