E-Trade は最近 API をリリースし、ある程度役立つが完全ではない技術文書を提供しました。
これがどのように機能するかを示す、C# で完全に機能する例を誰かが持っていますか?
OAuth を使用して認証を正しく行うことができましたが、アカウントまたは市場データから情報を取得しようとすると、サーバーに障害が発生します。
E-Trade は最近 API をリリースし、ある程度役立つが完全ではない技術文書を提供しました。
これがどのように機能するかを示す、C# で完全に機能する例を誰かが持っていますか?
OAuth を使用して認証を正しく行うことができましたが、アカウントまたは市場データから情報を取得しようとすると、サーバーに障害が発生します。
DevDefined OAuth Library を使用して接続できましたが、ソースを適切に機能させるには、ソースを微調整する必要がありました。私が使用した src をダウンロードして .dll をビルドできるように、リポジトリをフォークしました。
レポ: GitHub
例のクラス:
public abstract class BaseOAuthRepository
{
private static string REQUEST_URL = "https://etws.etrade.com/oauth/request_token";
private static string AUTHORIZE_URL = "https://us.etrade.com/e/t/etws/authorize";
private static string ACCESS_URL = "https://etws.etrade.com/oauth/access_token";
private readonly TokenBase _tokenBase;
private readonly string _consumerSecret;
protected BaseOAuthRepository(TokenBase tokenBase,
string consumerSecret)
{
_tokenBase = tokenBase;
_consumerSecret = consumerSecret;
}
public TokenBase MyTokenBase
{
get { return _tokenBase; }
}
public string MyConsumerSecret
{
get { return _consumerSecret; }
}
public OAuthSession CreateSession()
{
var consumerContext = new OAuthConsumerContext
{
ConsumerKey = MyTokenBase.ConsumerKey,
ConsumerSecret = MyConsumerSecret,
SignatureMethod = SignatureMethod.HmacSha1,
UseHeaderForOAuthParameters = true,
CallBack = "oob"
};
var session = new OAuthSession(consumerContext, REQUEST_URL, AUTHORIZE_URL, ACCESS_URL);
return session;
}
public IToken GetAccessToken(OAuthSession session)
{
IToken requestToken = session.GetRequestToken();
string authorizationLink = session.GetUserAuthorizationUrlForToken(MyTokenBase.ConsumerKey, requestToken);
Process.Start(authorizationLink);
Console.Write("Please enter pin from browser: ");
string pin = Console.ReadLine();
IToken accessToken = session.ExchangeRequestTokenForAccessToken(requestToken, pin.ToUpper());
return accessToken;
}
public string GetResponse(OAuthSession session, string url)
{
IToken accessToken = MyTokenBase;
var response = session.Request(accessToken).Get().ForUrl(url).ToString();
return response;
}
public XDocument GetWebResponseAsXml(HttpWebResponse response)
{
XmlReader xmlReader = XmlReader.Create(response.GetResponseStream());
XDocument xdoc = XDocument.Load(xmlReader);
xmlReader.Close();
return xdoc;
}
public string GetWebResponseAsString(HttpWebResponse response)
{
Encoding enc = System.Text.Encoding.GetEncoding(1252);
StreamReader loResponseStream = new
StreamReader(response.GetResponseStream(), enc);
return loResponseStream.ReadToEnd();
}
}
ETrade API に接続するために使用したコードを次に示します (テスト済みで動作します)。
1 つの注意点: ユーザー トークンの独自のストレージを実装する必要があります。私が作成したコードは非常にドメイン固有であるため、ここには含めません。
最初にDotNetOpenAuth
、プロジェクトに追加して作成しましたETradeConsumer
(DotNetOpenAuth の WebConsumer から派生します)。
EtradeConsumer.cs
public static class ETradeConsumer
{
public static string AccessUrl
{
get
{
return "https://etws.etrade.com/oauth/access_token";
}
}
public static string RequestUrl
{
get
{
return "https://etws.etrade.com/oauth/request_token";
}
}
public static string UserAuthorizedUrl
{
get
{
return "https://us.etrade.com/e/t/etws/authorize";
}
}
private static readonly ServiceProviderDescription ServiceProviderDescription = new ServiceProviderDescription()
{
AccessTokenEndpoint = new MessageReceivingEndpoint(AccessUrl, HttpDeliveryMethods.PostRequest | HttpDeliveryMethods.AuthorizationHeaderRequest),
ProtocolVersion = ProtocolVersion.V10a,
RequestTokenEndpoint = new MessageReceivingEndpoint(RequestUrl, HttpDeliveryMethods.PostRequest | HttpDeliveryMethods.AuthorizationHeaderRequest),
TamperProtectionElements = new ITamperProtectionChannelBindingElement[] { new HmacSha1SigningBindingElement() },
UserAuthorizationEndpoint = new MessageReceivingEndpoint(new Uri(UserAuthorizedUrl), HttpDeliveryMethods.GetRequest | HttpDeliveryMethods.AuthorizationHeaderRequest)
};
public static DesktopConsumer CreateConsumer(IConsumerTokenManager tokenManager)
{
return new DesktopConsumer(ServiceProviderDescription, tokenManager);
}
public static Uri PrepareRequestAuthorization(DesktopConsumer consumer, out string requestToken)
{
if (consumer == null)
{
throw new ArgumentNullException("consumer");
}
Uri authorizationUrl = consumer.RequestUserAuthorization(null, null, out requestToken);
authorizationUrl = new Uri(string.Format("{0}?key={1}&token={2}", ServiceProviderDescription.UserAuthorizationEndpoint.Location.AbsoluteUri, consumer.TokenManager.ConsumerKey, requestToken));
return authorizationUrl;
}
public static AuthorizedTokenResponse CompleteAuthorization(DesktopConsumer consumer, string requestToken, string userCode)
{
var customServiceDescription = new ServiceProviderDescription
{
RequestTokenEndpoint = ServiceProviderDescription.RequestTokenEndpoint,
UserAuthorizationEndpoint =
new MessageReceivingEndpoint(
string.Format("{0}?key={1}&token={2}", ServiceProviderDescription.UserAuthorizationEndpoint.Location.AbsoluteUri,
consumer.TokenManager.ConsumerKey, requestToken),
HttpDeliveryMethods.AuthorizationHeaderRequest | HttpDeliveryMethods.GetRequest),
AccessTokenEndpoint = new MessageReceivingEndpoint(
ServiceProviderDescription.AccessTokenEndpoint.Location.AbsoluteUri + "?oauth_verifier" + userCode + string.Empty,
HttpDeliveryMethods.AuthorizationHeaderRequest | HttpDeliveryMethods.GetRequest),
TamperProtectionElements = ServiceProviderDescription.TamperProtectionElements,
ProtocolVersion = ProtocolVersion.V10a
};
var customConsumer = new DesktopConsumer(customServiceDescription, consumer.TokenManager);
var response = customConsumer.ProcessUserAuthorization(requestToken, userCode);
return response;
}
}
次に、Etrade トークンを管理するクラスを作成する必要があります。例として、次のクラスを作成しました。InMemoryCollection を介してトークンを管理しますが、ユーザーが毎回認証/承認する必要がないように、実際には別の場所 (データベース、Cookie、または何か) に保持する必要があります。ConsumerKey
およびトークンは、ConsumerSecret
Etrade を通じてサインアップするものです。
public class ETradeTokenManager : IConsumerTokenManager
{
private Dictionary<string, string> tokensAndSecrets = new Dictionary<string, string>();
public string ConsumerKey { get { return "YourConsumerKey"; } }
public string ConsumerSecret { get { return "YourConsumerSecret"; } }
public string GetTokenSecret(string token)
{
return tokensAndSecrets[token];
}
public void StoreNewRequestToken(UnauthorizedTokenRequest request, ITokenSecretContainingMessage response)
{
tokensAndSecrets[response.Token] = response.TokenSecret;
}
public void ExpireRequestTokenAndStoreNewAccessToken(string consumerKey, string requestToken, string accessToken, string accessTokenSecret)
{
tokensAndSecrets.Remove(requestToken);
tokensAndSecrets[accessToken] = accessTokenSecret;
}
public TokenType GetTokenType(string token)
{
throw new NotImplementedException();
}
}
最後に、以下を入力します (私は ASP.NET MVC 3 を使用しました。フレームワークは異なる場合があります)。
public ActionResult EtradeAuthorize(string returnUrl)
{
var consumer = ETradeConsumer.CreateConsumer(TokenManager);
string requestToken;
Uri popupWindow = ETradeConsumer.PrepareRequestAuthorization(consumer, out requestToken);
var etradeViewModel = new ETradeAuthorizeViewModel(popupWindow, requestToken);
return View(etradeViewModel);
}
[HttpPost]
public ActionResult CompleteAuthorization(FormCollection formCollection)
{
string accessToken = "";
var consumer = ETradeConsumer.CreateConsumer(TokenManager);
var authorizationReponse = ETradeConsumer.CompleteAuthorization(consumer, formCollection["requestToken"], formCollection["userCode"]);
if (authorizationReponse != null)
{
accessToken = authorizationReponse.AccessToken;
}
var etradeViewModel = new ETradeCompleteAuthorizeViewModel(formCollection["requestToken"], formCollection["userCode"], accessToken);
return View(etradeViewModel);
}
を取得した場合は、Etrade400 Bad Request
を取り出します。callbackUrl
何らかの理由で、コールバック URL が使用されるたびに不正なリクエストがスローされます。彼らはoob
(帯域外)を好みます。を使用するには、メソッド内の Callback URL にoob
設定します。null
Consumer.Channel.Send()
他にも問題があります。この問題:通話の一部が適切に処理されていないことDue to a logon delay or other issue, your authentication could not be completed at this time. Please try again.
が原因です。authorize
具体的には、Etrade では、認証 URL が次のようになっている必要があります。
https://us.etrade.com/e/t/etws/authorize?key={yourConsumerKey}&token={requestToken}
OAuth 仕様では、リクエスト トークンは である必要がrequest_token={requestToken}
あり、 ではない必要がありtoken={requestToken}
ます。
で Etrade API を正しく認証できませんでしたWebConsumer
が、 に切り替えてDesktop Consumer
自分でリクエストを操作すると、正しく機能しました。
「ログオンの遅延またはその他の問題により、現時点で認証を完了できませんでした。もう一度お試しください。」というメッセージが表示された場合、
次に、承認URLに間違ったキーを入れたと思います。
この形式の適切なキーを置き換えて、ドキュメントに従う必要があります
jejernigの回答からのサンプルクラス+GitHubのコードを使用するために、次を使用しました。
TokenBase token = new TokenBase { ConsumerKey = "oauth_consumer_key from ETRADE" }; // OAuthRepository only seems to use the consumer key
OAuthRepository rep = new OAuthRepository(token, "consumer_secret from ETRADE");
OAuthSession session = rep.CreateSession();
IToken accessToken = rep.GetAccessToken(session);
を削除しましたabstract
がBaseOAuthRepository
、のパラメータが逆になっているため、GitHubコードを修正する必要がありました IOAuthSession.GetUserAuthorizationUrlForToken()
(インターフェイスのパラメータに一致するように残りのコードを変更しました)。
恐ろしいDue to a logon delay or other issue, your authentication could not be completed at this time. Please try again.
メッセージが表示されますが、これは実際のログオンの問題が原因である可能性があり、解決する必要があります。
Cookie をクリアして、もう一度お試しください。なぜこれが起こるのかわかりません。ただし、このエラーが発生すると、Cookie をクリアしない限り、同じエラーが発生します。ログインに成功し、REST サービスの一部を呼び出すことができます。