有使用OAuth2访问Quickbooks API的简单方法吗?

时间:2019-01-26 17:54:39

标签: c# quickbooks-online

我只需要使用带有C#的API来访问我的Quickbooks Online(QBO)公司中的数据。但是现在他们已经迁移到OAuth2,它看起来非常复杂。例如,它建议我需要一个重定向URI来接收授权代码,但是我正在编写一个简单的控制台应用程序以将数据导出到QBO,并且不想托管一个URI端点来这样做。

知道如何获取和管理以下内容也令人困惑:

  • 客户ID
  • 客户秘密
  • RealmID
  • 授权码
  • 刷新令牌
  • 访问令牌

必须有一种简单的方法来执行此操作。例如,使用Stripe,您只需管理一个API密钥。

2 个答案:

答案 0 :(得分:0)

经过一些研究,我发现这可以通过简单的方式完成。您只需要保留刷新令牌的副本(也许在读/写文件中)。当您要访问API时,只需调用OAuth2Client.RefreshTokenAsync()即可获取访问令牌。其他所有必需项都可以在OAuth2游乐场中找到。

然后,访问令牌可以与API一起使用长达一小时。您还可以取回更新的刷新令牌。如果发生这种情况,请将其存储以备将来使用。在您必须使用从“刷新令牌”操作返回的较新版本之前,刷新令牌持续长达100天。

有关如何使用C#中的API的较长版本:

  1. 创建一个应用,但不要在QBO应用商店中发布。为此登录 使用您的QBO帐户的developer.intuit.com。转到“我的应用”,然后创建一个应用(例如,名为“ MyQBOApiApp ”)。这仅需要执行一次。将默认重定向URL设置为OAuth2游乐场,因为这是唯一需要的重定向URL。

  2. 从“ OAuth 2.0密钥”标签的“生产密钥”部分获取应用的生产客户端ID 客户端密钥。 (将它们记录下来,以便在C#程序中使用,因为它们不会更改)

  3. 转到https://developer.intuit.com/v2/ui#/playground的OAuth 2.0游乐场

  4. 在步骤1“获取授权码”中,从下拉列表框中选择MyQBOApiApp(Production)

  5. 如果您只需要向QBO公司读取/写入数据,请在“选择范围”列表中选择“会计”

  6. 点击“获取授权码”

  7. 将您的QBO公司连接到MyQBOApiApp应用

  8. 在操场上页面的第2步“从身份验证代码获取OAuth 2.0令牌”中,点击“获取令牌” 。这将为您对公司的API访问获得刷新令牌。

  9. 跳到游乐场页面上的第4步“刷新访问令牌”。访问令牌只能使用59分钟 因此只需保留“刷新令牌” ,因为它可以使用100天来获取新的访问令牌和刷新令牌。将其存储在您的C#程序可以读取和写入的位置(例如文件或数据库)

  10. 领域ID 可从步骤3中获得。“进行API调用”。 (将其记录下来,以便在C#程序中使用,因为它不会更改)

  11. 将IppDotNetSdkForQuickBooksApiV3 NuGet程序包添加到C#程序中。为了提供对API的轻松访问。

  12. 确保您使用的是.Net Framework 4.6.1或更高版本,因为QBO需要TLS 1.2连接

  13. 不幸的是,.Net控制台应用程序默认情况下不使用TLS 1.2。因此,请将这行代码添加到C#程序的启动位置:

    // Have to explicitly set TLS 1.2 as QBO APIs require it
    System.Net.ServicePointManager.SecurityProtocol = System.Net.SecurityProtocolType.Tls12;
    

在访问API之前,您将需要以下代码来获取访问令牌:

public static string GetAccessToken()
{
    var oauth2Client = new OAuth2Client(CLIENTID_FROM_STEP_2, 
            CLIENT_SECRET_FROM_STEP_2,
            // Redirect not used but matches entry for app
            "https://developer.intuit.com/v2/OAuth2Playground/RedirectUrl",
            "production"); // environment is “sandbox” or “production”

    var previousRefreshToken = ReadRefreshTokenFromWhereItIsStored();
    var tokenResp = oauth2Client.RefreshTokenAsync(previousRefreshToken );
    tokenResp.Wait();
    var data = tokenResp.Result;

    if ( !String.IsNullOrEmpty(data.Error) || String.IsNullOrEmpty(data.RefreshToken) || 
          String.IsNullOrEmpty(data.AccessToken))
    {
        throw new Exception("Refresh token failed - " + data.Error);
    }

    // If we've got a new refresh_token store it in the file
    if (previousRefreshToken != data.RefreshToken)
    {
        Console.WriteLine("Writing new refresh token : " + data.RefreshToken);
        WriteNewRefreshTokenToWhereItIsStored(data.RefreshToken)

    }
    return data.AccessToken;
}

您需要编写函数 ReadRefreshTokenFromWhereItIsStored() WriteNewRefreshTokenToWhereItIsStored(),以从持久性存储中加载和保存刷新令牌。

QBO中的所有API访问均始于服务上下文。您可以使用以下代码创建一个代码:

static public ServiceContext GetServiceContext()
{
    var accessToken = GetAccessToken(); // Code from above
    var oauthValidator = new OAuth2RequestValidator(accessToken);

    ServiceContext qboContext = new ServiceContext(REALMID_PROD_FROM_STEP10,
            IntuitServicesType.QBO, oauthValidator);

    return qboContext;
}

要访问数据,您可以创建数据服务,如下所示:

var service = new DataService(GetServiceContext());

答案 1 :(得分:0)

[HttpPost("qb/refresh-token")]
        public async Task<ActionResult> GetRefressToken()
        {
            JObject result = new JObject();
            //Request Oauth2 tokens
            var tokenClient = new OAuth2Client(
                "your client id",
                "secret",
                "https://developer.intuit.com/v2/OAuth2Playground/RedirectUrl",
                "sandbox"); // environment is “sandbox” or “production”

                    
            var previousRefreshToken = "your refresh token id ";Get it from Playgroud for first time**strong text**//ReadRefreshTokenFromWhereItIsStored();
            var tokenResp = await tokenClient.RefreshTokenAsync(previousRefreshToken);
           

            if (!String.IsNullOrEmpty(tokenResp.Error) || String.IsNullOrEmpty(tokenResp.RefreshToken) ||
                  String.IsNullOrEmpty(tokenResp.AccessToken))
            {
                throw new Exception("Refresh token failed - " + tokenResp.Error);
            }

            // If we've got a new refresh_token store it in the file
            if (previousRefreshToken != tokenResp.RefreshToken)
            {
                Console.WriteLine("Writing new refresh token : " + tokenResp.RefreshToken);
                //WriteNewRefreshTokenToWhereItIsStored(data.RefreshToken);
             
            }
            return Ok(tokenResp.AccessToken);
            //return new Tuple<string, string>(tokenResp.RefreshToken, tokenResp.AccessToken);
        }