文档签名服务集成真实账户无法进行身份验证



我已经构建了一个 DocuSign 集成,可以很好地与沙盒帐户配合使用,但我在使用真实帐户时遇到了问题。我正在使用 C# SDK。我正在使用带有模拟的授权代码授予。调试显示已创建一个LoginInformation对象,但它的 LoginAccounts 属性为 null,这当然会破坏尝试为后续 API 调用获取相应基本 URL 的代码。有什么建议吗?

public static ApiClient GetDocuSignClient()
{
string accountType = SettingsKeyInfoProvider.GetValue(SiteContext.CurrentSiteName + ".DocuSignAccountType");
string integratorKey = SettingsKeyInfoProvider.GetValue(SiteContext.CurrentSiteName + ".DocuSignIntegratorKey");
string userID = SettingsKeyInfoProvider.GetValue(SiteContext.CurrentSiteName + ".DocuSignUserID");
string rsaPrivate = SettingsKeyInfoProvider.GetValue(SiteContext.CurrentSiteName + ".DocuSignRSAKey");
string basePath = accountType == "sandbox" ? "account-d.docusign.com" : "account.docusign.com";
// this gets replaced when we communicate with the api
string clientBasePath = accountType == "sandbox" ? "https://demo.docusign.net/restapi" : "https://www.docusign.net/restapi";
int expirationHours = 1;
if (accountType == "" || integratorKey == "" || userID == "" || rsaPrivate == "")
throw new System.Configuration.ConfigurationErrorsException("All DocuSign settings must be set in Settings->Integration->DocuSign");
ApiClient dsClient = new ApiClient(clientBasePath);
dsClient.ConfigureJwtAuthorizationFlow(integratorKey, userID, basePath, HttpContext.Current.Server.MapPath(rsaPrivate), expirationHours);

AuthenticationApi authClient = new AuthenticationApi(dsClient.Configuration);
LoginInformation loginInfo = authClient.Login();
// find the default account for this user
foreach (LoginAccount loginAcct in loginInfo.LoginAccounts)
{
...

根据我们的 DS 文档,使用 OAUTH(和 JWT(,您不应该使用 Login_information API,而是需要使用用户信息 API 调用来获取基本 URI。获取基本 URI 后,使用此基本 URI 执行所有其他与身份验证无关的 API。演示环境仅在一个数据中心,因此使用您当前的代码,它在沙盒中运行良好,但 PROD 有多个数据中心,如 NA1、NA2、NA3、EU1,并且您的帐户可以在其中任何一个中,因此要知道用于命中数据中心以创建信封的确切 URI,您需要使用用户信息 API 调用来了解基本 URI。

目前在您的代码中,您已经硬编码了 BaseUri(或客户端基本路径(clientBasePath = https://www.docusign.net/restapi,在此硬编码中,您假设您的 PROD 帐户位于 NA1 中,但正如我之前提到的,它也可以在任何其他数据中心中,因此请更改代码以调用 userinfo/API 调用。我们的 SDK 有此代码(错误地调用 LoginInformation 而不是 userinfo/(编写不正确,我已经将其报告给 DS 开发人员中心团队以修复此流程。

我在DocuSign API文档中发现了错误或非常误导性的陈述。似乎 oauth/userinfo 调用以沙盒和实时帐户的不同格式返回帐户的基本 URL。下面的代码有点混乱,但它对两者都有效。

public static ApiClient GetDocuSignClient()
{
string accountType = SettingsKeyInfoProvider.GetValue(SiteContext.CurrentSiteName + ".DocuSignAccountType");
string integratorKey = SettingsKeyInfoProvider.GetValue(SiteContext.CurrentSiteName + ".DocuSignIntegratorKey");
string userID = SettingsKeyInfoProvider.GetValue(SiteContext.CurrentSiteName + ".DocuSignUserID");
string rsaPrivate = SettingsKeyInfoProvider.GetValue(SiteContext.CurrentSiteName + ".DocuSignRSAKey");
string basePath = accountType == "sandbox" ? "account-d.docusign.com" : "account.docusign.com";
// this gets replaced when we communicate with the api
string clientBasePath = accountType == "sandbox" ? "https://demo.docusign.net/restapi" : "https://www.docusign.net/restapi";
int expirationHours = 1;
if (accountType == "" || integratorKey == "" || userID == "" || rsaPrivate == "")
throw new System.Configuration.ConfigurationErrorsException("All DocuSign settings must be set in Settings->Integration->DocuSign");
ApiClient dsClient = new ApiClient(clientBasePath);
dsClient.ConfigureJwtAuthorizationFlow(integratorKey, userID, basePath, HttpContext.Current.Server.MapPath(rsaPrivate), expirationHours);
var rsUserClient = new RestSharp.RestClient("https://" + basePath); ;
RestSharp.RestRequest acctReq = new RestSharp.RestRequest();
acctReq.Method = RestSharp.Method.GET;
acctReq.RequestFormat = RestSharp.DataFormat.Json;
acctReq.Resource = "oauth/userinfo";
// even though we're not using the SDK to get accounts, we can use the token it generates
AuthenticationApi authClient = new AuthenticationApi(dsClient.Configuration);
acctReq.AddHeader("Authorization", authClient.Configuration.DefaultHeader["Authorization"]);

RestSharp.IRestResponse rsResponse = rsUserClient.Execute(acctReq);
if (rsResponse.ResponseStatus != RestSharp.ResponseStatus.Completed || rsResponse.StatusCode != HttpStatusCode.OK)
{
if (rsResponse.ErrorException != null)
throw new WebException("DocuSign login failed: " + rsResponse.ErrorException.Message, rsResponse.ErrorException);
else if (rsResponse.StatusCode == HttpStatusCode.BadRequest)
throw new WebException(String.Format("DocuSign login failed. StatusCode: {0} <br/>ErrorDescription: {1}", rsResponse.StatusCode, rsResponse.Content));
else
throw new WebException(String.Format("DocuSign login failed. StatusCode: {0} ResponseStatus: {1}", rsResponse.StatusCode, rsResponse.ResponseStatus));
}
DocuSignLoginInfo loginInfo = JsonConvert.DeserializeObject<DocuSignLoginInfo>(rsResponse.Content);
DocuSignLoginAccount toUse = null;
foreach (var loginAcct in loginInfo.Accounts)
{
if (toUse == null)
{
toUse = loginAcct; // use first account
}
else if (loginAcct.IsDefault && 
((accountType == "sandbox" && loginAcct.Base_Uri.Contains("demo.")) || 
(accountType != "sandbox" && !loginAcct.Base_Uri.Contains("demo."))))
{
toUse = loginAcct; // use default account if appropriate
}
}
if (toUse == null)
{
throw new WebException("DocuSign login failed: " + loginInfo.Email + " doesn't have a login account we can use.");
}
else
{
SettingsKeyInfoProvider.SetValue("DocuSignAccountID", SiteContext.CurrentSiteName, toUse.Account_Id);
string[] separatingStrings = { "/v2" };
string restUrl = toUse.Base_Uri.Split(separatingStrings, StringSplitOptions.RemoveEmptyEntries)[0];
if (!restUrl.Contains("/restapi"))
restUrl += "/restapi";
// Update ApiClient with the new base url from login call
dsClient = new ApiClient(restUrl);
}

return dsClient;
}
public class DocuSignLoginAccount
{
public string Account_Id;
public string Account_Name;
public bool IsDefault;
public string Base_Uri;
}
public class EnvelopeBrief
{
public string EnvID;
public Signer CurrentSigner;
public string ClientUserID;
}

最新更新