我正在使用QBO API SDK(IppDotNetSdkQuickBooksApiV3),无法弄清楚如何允许用户连接到QuickBooks并授权我的应用程序。目前,这是通过两(2)个步骤进行的:
我显然缺少某些东西,但不知道它是什么。我正在使用该应用程序内置的ipp:connecttointuit功能,所以我不知道如何针对我要的结果对其进行自定义。
我的应用程序可以完成上述两个步骤,但是我无法使用上面详述的过程在apps.com网站上列出我的应用程序。他们(apps.com)希望用户使用其QBO凭据登录,授权应用程序,然后在应用程序正常运行时自动将用户重定向回我的网站。他们不希望重复授权(我不能怪他们)。
完全卡住。我是一名不错的程序员,但没有使用OpenId或OAuth的经验。
protected void Page_Load(object sender, EventArgs e)
{
var openIdRelyingParty = new OpenIdRelyingParty();
var openid_identifier = ConfigurationManager.AppSettings["openid_identifier"];
var returnUrl = "~/OpenID/Connect";
var response = openIdRelyingParty.GetResponse();
if (response == null)
{
// Stage 2: user submitting Identifier
Identifier id;
if (Identifier.TryParse(openid_identifier, out id))
{
IAuthenticationRequest request = openIdRelyingParty.CreateRequest(openid_identifier);
FetchRequest fetch = new FetchRequest();
fetch.Attributes.Add(new AttributeRequest(WellKnownAttributes.Contact.Email));
fetch.Attributes.Add(new AttributeRequest(WellKnownAttributes.Name.FullName));
fetch.Attributes.Add(new AttributeRequest("http://axschema.org/intuit/realmId"));
request.AddExtension(fetch);
request.RedirectToProvider();
}
}
else
{
if (response.FriendlyIdentifierForDisplay == null)
{
Response.Redirect("~/OpenID/Connect");
}
// Stage 3: OpenID Provider sending assertion response
//Session["FriendlyIdentifier"] = response.FriendlyIdentifierForDisplay;
FetchResponse fetch = response.GetExtension<FetchResponse>();
if (fetch != null)
{
var openIdEmail = fetch.GetAttributeValue(WellKnownAttributes.Contact.Email);
var openIdFullName = fetch.GetAttributeValue(WellKnownAttributes.Name.FullName);
var openIdRealmId = fetch.GetAttributeValue("http://axschema.org/intuit/realmId");
string userName = Membership.GetUserNameByEmail(openIdEmail);
//If username is null---------------------------------------------------
if (userName == null)
{
//DG added this---------------------------
String NewPassword = Membership.GeneratePassword(6, 1);
Membership.CreateUser(openIdEmail, NewPassword, openIdEmail);
//DG added this----------------------------
//Membership.CreateUser(openIdEmail, Guid.NewGuid().ToString(), openIdEmail);
FormsAuthentication.SetAuthCookie(openIdEmail, true);
//if (Request.QueryString["Subscribe"] != null)
//{
String csname = "DirectConnectScript";
Type cstype = this.GetType();
ClientScriptManager csm = Page.ClientScript;
// Check to see if the startup script is already registered.
if (!csm.IsStartupScriptRegistered(cstype, csname))
{
StringBuilder cstext = new StringBuilder();
cstext.AppendLine("<script>");
cstext.AppendLine("$(document).ready(function () {");
cstext.AppendLine("intuit.ipp.anywhere.directConnectToIntuit();");
cstext.AppendLine("});");
cstext.AppendLine("</script>");
csm.RegisterStartupScript(cstype, csname, cstext.ToString());
//}
}
}
else if (Request.QueryString["Disconnect"] != null)
{
RestHelper.clearProfile(RestProfile.GetRestProfile());
Response.Redirect("~/ManageConnection");
}
//If username is not null---------------------------------------------------
else if (userName != null)
{
FormsAuthentication.SetAuthCookie(userName, true);
if (!string.IsNullOrEmpty(returnUrl))
{
Response.Redirect("~/ManageConnection");
}
}
}
}
}
答案 0 :(得分:0)
我觉得对您来说,我花了一段时间才能自己完成这项工作。
这是我的MVC版本。希望对您有所帮助。
它以QuickBooks / Index开头。使用QB弹出窗口获取对我的应用程序的权限,然后从那里去。另外,如果用户已经登录到QB,则他们在过去曾被授予权限的情况下会自动登录到该应用程序。这是因为我将加密的令牌保留在数据库中。 (忽略大多数Session内容,我只是从未从创建代码的示例中将其删除)。
无论如何,这要发布很多代码。 如果您需要任何澄清,请随时在评论中提问
我假设您具有类似的内容,可以接收OAuthResponse并重定向回/ QuickBooks / Index(在您的情况下,您在问题中发布的页面)
public class OauthResponseController : Controller
{
/// <summary>
/// OAuthVerifyer, RealmId, DataSource
/// </summary>
private String _oauthVerifyer, _realmid, _dataSource;
/// <summary>
/// Action Results for Index, OAuthToken, OAuthVerifyer and RealmID is recieved as part of Response
/// and are stored inside Session object for future references
/// NOTE: Session storage is only used for demonstration purpose only.
/// </summary>
/// <returns>View Result.</returns>
public ViewResult Index()
{
if (Request.QueryString.HasKeys())
{
// This value is used to Get Access Token.
_oauthVerifyer = Request.QueryString.GetValues("oauth_verifier").FirstOrDefault().ToString();
if (_oauthVerifyer.Length == 1)
{
_oauthVerifyer = Request.QueryString["oauth_verifier"].ToString();
}
_realmid = Request.QueryString.GetValues("realmId").FirstOrDefault().ToString();
if (_realmid.Length == 1)
{
_realmid = Request.QueryString["realmId"].ToString();
}
Session["Realm"] = _realmid;
//If dataSource is QBO call QuickBooks Online Services, else call QuickBooks Desktop Services
_dataSource = Request.QueryString.GetValues("dataSource").FirstOrDefault().ToString();
if (_dataSource.Length == 1)
{
_dataSource = Request.QueryString["dataSource"].ToString();
}
Session["DataSource"] = _dataSource;
getAccessToken();
//Production applications should securely store the Access Token.
//In this template, encrypted Oauth access token is persisted in OauthAccessTokenStorage.xml
OauthAccessTokenStorageHelper.StoreOauthAccessToken();
// This value is used to redirect to Default.aspx from Cleanup page when user clicks on ConnectToInuit widget.
Session["RedirectToDefault"] = true;
}
else
{
Response.Write("No oauth token was received");
}
return View(); // This will redirect to /QuickBooks/OpenIdIndex which is almost the same as the code that you have posted
}
/// <summary>
/// Gets the OAuth Token
/// </summary>
private void getAccessToken()
{
IOAuthSession clientSession = CreateSession();
try
{
IToken accessToken = clientSession.ExchangeRequestTokenForAccessToken((IToken)Session["requestToken"], _oauthVerifyer);
Session["AccessToken"] = accessToken.Token;
// Add flag to session which tells that accessToken is in session
Session["Flag"] = true;
// Remove the Invalid Access token since we got the new access token
Session.Remove("InvalidAccessToken");
Session["AccessTokenSecret"] = accessToken.TokenSecret;
}
catch (Exception ex)
{
//Handle Exception if token is rejected or exchange of Request Token for Access Token failed.
throw ex;
}
}
/// <summary>
/// Creates User Session
/// </summary>
/// <returns>OAuth Session.</returns>
private IOAuthSession CreateSession()
{
OAuthConsumerContext consumerContext = new OAuthConsumerContext
{
ConsumerKey = ConfigurationManager.AppSettings["consumerKey"].ToString(),
ConsumerSecret = ConfigurationManager.AppSettings["consumerSecret"].ToString(),
SignatureMethod = SignatureMethod.HmacSha1
};
return new OAuthSession(consumerContext,
Constants.OauthEndPoints.IdFedOAuthBaseUrl + Constants.OauthEndPoints.UrlRequestToken,
Constants.OauthEndPoints.IdFedOAuthBaseUrl,
Constants.OauthEndPoints.IdFedOAuthBaseUrl + Constants.OauthEndPoints.UrlAccessToken);
}
}
这是我的等效页面。
public class QuickBooksController : Controller
{
private readonly IQueryChannel _queryChannel;
private readonly ICommandChannel _commandChannel;
public QuickBooksController(IQueryChannel queryChannel, ICommandChannel commandChannel)
{
_queryChannel = queryChannel;
_commandChannel = commandChannel;
}
/// <summary>
/// OpenId Relying Party
/// </summary>
private static OpenIdRelyingParty openid = new OpenIdRelyingParty();
public ActionResult Index(string returnurl)
{
QuickBooksAuthStore.Load();
if (QuickBooksContext.AccessToken != null)
{
if (!new Customers().CheckConnection())
{
QuickBooksContext.FriendlyName = null;
OauthAccessTokenStorageHelper.RemoveInvalidOauthAccessToken(QuickBooksContext.FriendlyEmail);
QuickBooksContext.AccessToken = null;
}
}
if (returnurl != null || QuickBooksContext.QuickReturnUrl != null)
{
if (returnurl != null)
{
QuickBooksContext.QuickReturnUrl = returnurl;
}
if (QuickBooksContext.AccessToken != null)
{
var connected = new Customers().CheckConnection();
if (connected)
{
returnurl = QuickBooksContext.QuickReturnUrl;
QuickBooksContext.QuickReturnUrl = null;
return Redirect(returnurl);
}
}
}
return View();
}
public RedirectResult OpenIdIndex()
{
var openid_identifier = ConfigurationManager.AppSettings["openid_identifier"] + SessionContext.CurrentUser.MasterCompanyId;
var response = openid.GetResponse();
if (response == null)
{
// Stage 2: user submitting Identifier
Identifier id;
if (Identifier.TryParse(openid_identifier, out id))
{
try
{
IAuthenticationRequest request = openid.CreateRequest(openid_identifier);
FetchRequest fetch = new FetchRequest();
fetch.Attributes.Add(new AttributeRequest(WellKnownAttributes.Contact.Email));
fetch.Attributes.Add(new AttributeRequest(WellKnownAttributes.Name.FullName));
request.AddExtension(fetch);
request.RedirectToProvider();
}
catch (ProtocolException ex)
{
throw ex;
}
}
}
else
{
if (response.FriendlyIdentifierForDisplay == null)
{
Response.Redirect("/OpenId");
}
// Stage 3: OpenID Provider sending assertion response, storing the response in Session object is only for demonstration purpose
Session["FriendlyIdentifier"] = response.FriendlyIdentifierForDisplay;
FetchResponse fetch = response.GetExtension<FetchResponse>();
if (fetch != null)
{
Session["OpenIdResponse"] = "True";
Session["FriendlyEmail"] = fetch.GetAttributeValue(WellKnownAttributes.Contact.Email);// emailAddresses.Count > 0 ? emailAddresses[0] : null;
Session["FriendlyName"] = fetch.GetAttributeValue(WellKnownAttributes.Name.FullName);//fullNames.Count > 0 ? fullNames[0] : null;
OauthAccessTokenStorageHelper.GetOauthAccessTokenForUser(Session["FriendlyEmail"].ToString());
QuickBooksAuthStore.UpdateFriendlyId(Session["FriendlyIdentifier"].ToString(), Session["FriendlyName"].ToString());
}
}
string query = Request.Url.Query;
if (!string.IsNullOrWhiteSpace(query) && query.ToLower().Contains("disconnect=true"))
{
Session["AccessToken"] = "dummyAccessToken";
Session["AccessTokenSecret"] = "dummyAccessTokenSecret";
Session["Flag"] = true;
return Redirect("QuickBooks/CleanupOnDisconnect");
}
return Redirect("/QuickBooks/Index");
}
/// <summary>
/// Service response.
/// </summary>
private String txtServiceResponse = "";
/// <summary>
/// Disconnect Flag.
/// </summary>
protected String DisconnectFlg = "";
public ActionResult Disconnect()
{
OAuthConsumerContext consumerContext = new OAuthConsumerContext
{
ConsumerKey = ConfigurationManager.AppSettings["consumerKey"].ToString(),
SignatureMethod = SignatureMethod.HmacSha1,
ConsumerSecret = ConfigurationManager.AppSettings["consumerSecret"].ToString()
};
OAuthSession oSession = new OAuthSession(consumerContext, Constants.OauthEndPoints.IdFedOAuthBaseUrl + Constants.OauthEndPoints.UrlRequestToken,
Constants.OauthEndPoints.AuthorizeUrl,
Constants.OauthEndPoints.IdFedOAuthBaseUrl + Constants.OauthEndPoints.UrlAccessToken);
oSession.ConsumerContext.UseHeaderForOAuthParameters = true;
if ((Session["AccessToken"] + "").Length > 0)
{
Session["FriendlyName"] = null;
oSession.AccessToken = new TokenBase
{
Token = Session["AccessToken"].ToString(),
ConsumerKey = ConfigurationManager.AppSettings["consumerKey"].ToString(),
TokenSecret = Session["AccessTokenSecret"].ToString()
};
IConsumerRequest conReq = oSession.Request();
conReq = conReq.Get();
conReq = conReq.ForUrl(Constants.IaEndPoints.DisconnectUrl);
try
{
conReq = conReq.SignWithToken();
}
catch (Exception ex)
{
throw ex;
}
//Used just see the what header contains
string header = conReq.Context.GenerateOAuthParametersForHeader();
//This method will clean up the OAuth Token
txtServiceResponse = conReq.ReadBody();
//Reset All the Session Variables
Session.Remove("oauthToken");
// Dont remove the access token since this is required for Reconnect btn in the Blue dot menu
// Session.Remove("accessToken");
// Add the invalid access token into session for the display of the Disconnect btn
Session["InvalidAccessToken"] = Session["AccessToken"];
// Dont Remove flag since we need to display the blue dot menu for Reconnect btn in the Blue dot menu
// Session.Remove("Flag");
ViewBag.DisconnectFlg = "User is Disconnected from QuickBooks!";
//Remove the Oauth access token from the OauthAccessTokenStorage.xml
OauthAccessTokenStorageHelper.RemoveInvalidOauthAccessToken(Session["FriendlyEmail"].ToString());
}
return RedirectToAction("Index", "QuickBooks");
}
public ActionResult CleanUpOnDisconnect()
{
//perform the clean up here
// Redirect to Home when user clicks on ConenctToIntuit widget.
object value = Session["RedirectToDefault"];
if (value != null)
{
bool isTrue = (bool)value;
if (isTrue)
{
Session.Remove("InvalidAccessToken");
Session.Remove("RedirectToDefault");
return Redirect("/QuickBooks/index");
}
}
return RedirectToAction("Index", "QuickBooks");
}
private String consumerSecret, consumerKey, oauthLink, RequestToken, TokenSecret, oauth_callback_url;
public RedirectResult OAuthGrant()
{
oauth_callback_url = Request.Url.GetLeftPart(UriPartial.Authority) + ConfigurationManager.AppSettings["oauth_callback_url"];
consumerKey = ConfigurationManager.AppSettings["consumerKey"];
consumerSecret = ConfigurationManager.AppSettings["consumerSecret"];
oauthLink = Constants.OauthEndPoints.IdFedOAuthBaseUrl;
IToken token = (IToken)Session["requestToken"];
IOAuthSession session = CreateSession();
IToken requestToken = session.GetRequestToken();
Session["requestToken"] = requestToken;
RequestToken = requestToken.Token;
TokenSecret = requestToken.TokenSecret;
oauthLink = Constants.OauthEndPoints.AuthorizeUrl + "?oauth_token=" + RequestToken + "&oauth_callback=" + UriUtility.UrlEncode(oauth_callback_url);
return Redirect(oauthLink);
}
/// <summary>
/// Gets the Access Token
/// </summary>
/// <returns>Returns OAuth Session</returns>
protected IOAuthSession CreateSession()
{
OAuthConsumerContext consumerContext = new OAuthConsumerContext
{
ConsumerKey = consumerKey,
ConsumerSecret = consumerSecret,
SignatureMethod = SignatureMethod.HmacSha1
};
return new OAuthSession(consumerContext,
Constants.OauthEndPoints.IdFedOAuthBaseUrl + Constants.OauthEndPoints.UrlRequestToken,
oauthLink,
Constants.OauthEndPoints.IdFedOAuthBaseUrl + Constants.OauthEndPoints.UrlAccessToken);
}
}
..这是QuickBooks / Index的cshtml页面
@using System.Configuration
@using PubManager.Domain.WebSession
@{
string MenuProxy = Request.Url.GetLeftPart(UriPartial.Authority) + "/" + System.Configuration.ConfigurationManager.AppSettings["menuProxy"];
string OauthGrant = Request.Url.GetLeftPart(UriPartial.Authority) + "/" + System.Configuration.ConfigurationManager.AppSettings["grantUrl"];
ViewBag.Title = "MagManager - Intuit Anywhere";
string FriendlyName = (string)HttpContext.Current.Session["FriendlyName"] + "";
string FriendlyEmail = (string)HttpContext.Current.Session["FriendlyEmail"];
string FriendlyIdentifier = (string)HttpContext.Current.Session["FriendlyIdentifier"];
string realm = (string)Session["Realm"];
string dataSource = (string)Session["DataSource"];
string accessToken = (string)Session["AccessToken"] + "";
string accessTokenSecret = (string)Session["AccessTokenSecret"];
string invalidAccessToken = (string)Session["InvalidAccessToken"];
}
<h1>Intuit - QuickBooks Online</h1>
<div class="well">
@if (FriendlyName.Length == 0)
{
<script>
window.location.href = "/QuickBooks/OpenIdIndex";
</script>
}
else
{
<div id="IntuitInfo">
<strong>Open Id Information:</strong><br />
Welcome: @FriendlyName<br />
E-mail Address: @FriendlyEmail<br />
<br />
@if (accessToken.Length > 0 && invalidAccessToken == null)
{
<div id="oAuthinfo">
<a onclick="reconcileInvoices()" id="RecInvoices" class="btn btn-primary">Set Invoices Paid</a><br />
<br/>
<a onclick="recTax()" id="RecTax" class="btn btn-primary">Sync Tax Rates</a><br />
<br/>
@if (SessionContext.UseAccountCodes)
{
<a onclick="recProducts()" id="RecProducts" class="btn btn-primary">Sync Products</a><br />
<br />
}
<a href="/QuickBooks/ReconcileCustomers" id="Customers" class="btn btn-primary">Reconcile Customers</a><br/>
<br/>
<a href="/QuickBooks/Disconnect" id="Disconnect" class="btn btn-primary">
Disconnect from
QuickBooks
</a>
<br/><br/>
@*<a href="/QuickBooks/Customers" id="QBCustomers" class="btn btn-primary">Get QuickBooks Customer List</a><br/>
<br/>*@
@*<br />
<a href="/QuickBooks/Invoices" id="QBInvoices" class="btn btn-primary">Get QuickBooks Invoice List</a><br />
<br />*@
<br />
</div>
}
else
{
<br />
<ipp:connecttointuit></ipp:connecttointuit>
}
</div>
}
</div>
<script type="text/javascript" src="https://js.appcenter.intuit.com/Content/IA/intuit.ipp.anywhere-1.3.5.js"></script>
<script type="text/javascript">
intuit.ipp.anywhere.setup({
menuProxy: '@MenuProxy',
grantUrl: '@OauthGrant'
});
</script>