2013-03-19 41 views
1

我設法整合了Facebook,Twitter和谷歌的預定義提供商。但我需要允許人們通過Paypal登錄。我創建了以下繼承自DotNetOpenAuth.AspNet.Clients.OAuth2Client的類。給定的關鍵是不存在的字典 -自定義DotnetOpenOauth貝寶客戶端(密鑰不存在)

using System; 
using System.Collections.Generic; 
using System.Diagnostics.CodeAnalysis; 
using System.Net; 
using System.Web; 
using Validation; 

using DotNetOpenAuth.AspNet; 
using DotNetOpenAuth.Messaging; 
using Newtonsoft.Json; 
using System.Text.RegularExpressions; 

namespace OauthClient 
{ 
    public class PayPalProviderClient : DotNetOpenAuth.AspNet.Clients.OAuth2Client 
    { 
     #region Oauth2 
     #region Constants and Fields 

     // https://www.x.com/developers/paypal/documentation-tools/quick-start-guides/oauth-openid-connect-integration-paypal#making-first-call-register 
     // 3 https://www.paypal.com/webapps/auth/protocol/openidconnect/v1/authorize?client_id=<your_app_id>&response_type=code&scope=openid&redirect_uri=https://www.example.com/my-redirect-uri 
     // 5 https://your-return-url?code=auth-code&scope=space-separted-scope-list&state=state 
     // 6 https://www.paypal.com/webapps/auth/protocol/openidconnect/v1/tokenservice 

     private const string AuthorizationEndpoint = "https://www.paypal.com/webapps/auth/protocol/openidconnect/v1/authorize?response_type=code&scope=openid&"; 
     private const string TokenEndpoint = "https://www.paypal.com/webapps/auth/protocol/openidconnect/v1/tokenservice"; 
     private const string UserDetailsEndPoint = "https://www.paypal.com/webapps/auth/protocol/openidconnect/v1/userinfo"; 

     private readonly string appId; 
     private readonly string appSecret; 


     #endregion 

     #region Constructors and Destructors 

     public PayPalProviderClient(string appId, string appSecret) : base("paypal") 
     { 
      Requires.NotNullOrEmpty(appId, "appId"); 
      Requires.NotNullOrEmpty(appSecret, "appSecret"); 
      this.appId = appId; 
      this.appSecret = appSecret; 
     } 

     #endregion 

     protected override Uri GetServiceLoginUrl(Uri returnUrl) 
     { 
      var builder = new UriBuilder(AuthorizationEndpoint); 
      builder.AppendQueryArgument("client_id", this.appId); 
      builder.AppendQueryArgument("redirect_uri", returnUrl.AbsoluteUri); 
      return builder.Uri; 
     } 

     protected override IDictionary<string, string> GetUserData(string accessToken) 
     { 
      var builder = new UriBuilder(UserDetailsEndPoint); 
      builder.AppendQueryArgument("schema", "openid"); 
      builder.AppendQueryArgument("access_token", accessToken); 

      Dictionary<string, string> userData = new Dictionary<string, string>(); 
      using (WebClient client = new WebClient()) 
      { 
       string data = client.DownloadString(builder.Uri); 
       if (string.IsNullOrEmpty(data)) 
        return null; 
       else 
        userData = JsonConvert.DeserializeObject<Dictionary<string, string>>(data); 
      } 
      return userData; 
     } 

     public override void RequestAuthentication(HttpContextBase context, Uri returnUrl) 
     { 
      base.RequestAuthentication(context, returnUrl); 
     } 

     private IDictionary<string, string> GetUserData(string accessCode, Uri redirectURI) 
     { 
      string token = QueryAccessToken(redirectURI, accessCode); 
      if (token == null || token == "") 
       return null; 
      return GetUserData(token); 
     } 

     private string QueryAccessToken(string returnUrl, string authorizationCode) 
     { 
      return QueryAccessToken(new Uri(returnUrl), authorizationCode); 
     } 

     protected override string QueryAccessToken(Uri returnUrl, string authorizationCode) 
     { 
      var builder = new UriBuilder(TokenEndpoint); 
      //"client_id=<your_app_id>&client_secret=<your_app_secret>&grant_type=authorization_code&code=<code>&redirect_uri=<urlencoded_return_url>" 
      builder.AppendQueryArgument("client_id", this.appId); 
      builder.AppendQueryArgument("client_secret", this.appSecret); 
      builder.AppendQueryArgument("grant_type", "authorization_code"); 
      builder.AppendQueryArgument("code", authorizationCode); 
      builder.AppendQueryArgument("redirect_uri", returnUrl.AbsoluteUri); 

      using (WebClient client = new WebClient()) 
      { 
       string data = client.DownloadString(builder.Uri); 
       if (string.IsNullOrEmpty(data)) 
        return null; 

       Dictionary<string, string> userData = JsonConvert.DeserializeObject<Dictionary<string, string>>(data); 
       if (userData.ContainsKey("access_token")) 
        return userData["access_token"].ToString(); 
       else 
        return string.Empty; 
      } 
     } 

     private string RefreshAccessToken(Uri returnUrl, string authorizationCode) 
     { 
      var builder = new UriBuilder(TokenEndpoint); 
      builder.AppendQueryArgument("client_id", this.appId); 
      builder.AppendQueryArgument("client_secret", this.appSecret); 
      builder.AppendQueryArgument("grant_type", "refresh_token"); 
      builder.AppendQueryArgument("code", authorizationCode); 
      builder.AppendQueryArgument("redirect_uri", returnUrl.AbsoluteUri); 

      using (WebClient client = new WebClient()) 
      { 
       string data = client.DownloadString(builder.Uri); 
       if (string.IsNullOrEmpty(data)) 
        return null; 

       Dictionary<string, string> userData = JsonConvert.DeserializeObject<Dictionary<string, string>>(data); 
       if (userData.ContainsKey("access_token")) 
        return userData["access_token"].ToString(); 
       else 
        return string.Empty; 
      } 
     } 
     #endregion 
    } 
} 

這是我的控制器

string callbackUrl = Url.Action("ExternalLoginCallback", new { ReturnUrl = returnUrl }); 
AuthenticationResult result = OAuthWebSecurity.VerifyAuthentication(callbackUrl); 

導致「System.Collections.Generic.KeyNotFoundException是由用戶代碼未處理」之稱。

有沒有人有與貝寶一起使用DNOA的工作示例?或者知道爲什麼我得到這個異常/我錯過了什麼關鍵?

UPDATE

我設法得到一個工作版本,請參見下面的代碼:

using System; 
using System.Collections.Generic; 
using System.Collections.Specialized; 
using System.IO; 
using System.Net; 
using System.Web; 
using DotNetOpenAuth.AspNet; 
using DotNetOpenAuth.AspNet.Clients; 
using DotNetOpenAuth.Messaging; 
using Newtonsoft.Json; 

namespace OauthClients 
{ 

    /// <summary> 
    /// A DotNetOpenAuth client for logging in to paypal using OAuth2. 
    /// Reference: https://developers.paypal.com/accounts/docs/OAuth2 
    /// </summary> 
    public class PaypalOAuth2Client : OAuth2Client 
    { 
     #region Constants and Fields 

     /// <summary> 
     /// The authorization endpoint. 
     /// </summary> 
     private const string AuthorizationEndpoint = "https://www.paypal.com/webapps/auth/protocol/openidconnect/v1/authorize?response_type=code&scope=openid&"; 

     /// <summary> 
     /// The token endpoint. 
     /// </summary> 
     private const string TokenEndpoint = "https://www.paypal.com/webapps/auth/protocol/openidconnect/v1/tokenservice"; 

     /// <summary> 
     /// The user info endpoint. 
     /// </summary> 
     private const string UserDetailsEndPoint = "https://www.paypal.com/webapps/auth/protocol/openidconnect/v1/userinfo"; 

     /// <summary> 
     /// The base uri for scopes. 
     /// </summary> 
     private const string ScopeBaseUri = "https://www.paypal.com/webapps/auth/"; 

     /// <summary> 
     /// The _app id. 
     /// </summary> 
     private readonly string _clientId; 

     /// <summary> 
     /// The _app secret. 
     /// </summary> 
     private readonly string _clientSecret; 

     /// <summary> 
     /// The requested scopes. 
     /// </summary> 
     private readonly string[] _requestedScopes; 

     #endregion 


     /// <summary> 
     /// Creates a new paypal OAuth2 client. 
     /// </summary> 
     /// <param name="clientId">The paypal Client Id</param> 
     /// <param name="clientSecret">The paypal Client Secret</param> 
     /// <param name="requestedScopes">One or more requested scopes, passed without the base URI.</param> 
     public PaypalOAuth2Client(string clientId, string clientSecret): base("paypal") 
     { 
      if (string.IsNullOrWhiteSpace(clientId)) 
       throw new ArgumentNullException("clientId"); 

      if (string.IsNullOrWhiteSpace(clientSecret)) 
       throw new ArgumentNullException("clientSecret"); 

      _clientId = clientId; 
      _clientSecret = clientSecret; 
     } 

     protected override Uri GetServiceLoginUrl(Uri returnUrl) 
     { 
      var builder = new UriBuilder(AuthorizationEndpoint); 
      builder.AppendQueryArgument("client_id", this._clientId); 
      builder.AppendQueryArgument("redirect_uri", returnUrl.AbsoluteUri); 

      return builder.Uri; 
     } 

     protected override IDictionary<string, string> GetUserData(string accessToken) 
     { 
      var request = WebRequest.Create(UserDetailsEndPoint + "?schema=openid&access_token=" + accessToken); 
      Dictionary<string, string> authData; 

      using (var response = request.GetResponse()) 
      using (var responseStream = response.GetResponseStream()) 
      using (var streamReader = new StreamReader(responseStream)) 
      { 
       authData = JsonConvert.DeserializeObject<Dictionary<string, string>>(streamReader.ReadToEnd()); 
       return authData; 
      } 
     } 

     protected override string QueryAccessToken(Uri returnUrl, string authorizationCode) 
     { 
      var builder = new UriBuilder(TokenEndpoint); 

      builder.AppendQueryArgument("client_id", this._clientId); 
      builder.AppendQueryArgument("client_secret", this._clientSecret); 
      builder.AppendQueryArgument("grant_type", "authorization_code"); 
      builder.AppendQueryArgument("code", authorizationCode); 
      builder.AppendQueryArgument("redirect_uri", returnUrl.AbsoluteUri); 


      using (WebClient client = new WebClient()) 
      { 
       var data = client.DownloadString(builder.Uri); 

       if (string.IsNullOrEmpty(data)) 
        return null; 

       Dictionary<string, string> userData = JsonConvert.DeserializeObject<Dictionary<string, string>>(data); 
       if (userData.ContainsKey("access_token")) 
        return userData["access_token"].ToString(); 
       else 
        return null; 
      } 
     } 

     public override AuthenticationResult VerifyAuthentication(HttpContextBase context, Uri returnPageUrl) 
     { 
      string code = context.Request.QueryString["code"]; 
      string u = context.Request.Url.ToString(); 

      if (string.IsNullOrEmpty(code)) 
       return AuthenticationResult.Failed; 

      string accessToken = this.QueryAccessToken(returnPageUrl, code); 
      if (accessToken == null) 
       return AuthenticationResult.Failed; 

      IDictionary<string, string> userData = this.GetUserData(accessToken); 
      if (userData == null) 
       return AuthenticationResult.Failed; 


      string id = userData["user_id"]; 
      string name = string.Empty ; 

      return new AuthenticationResult(
       isSuccessful: true, provider: "PayPal", providerUserId: id, userName: name, extraData: userData); 
     }  
    } 
} 

回答

0

你必須在你的方法提供關鍵=「ID」字典詞條GetUserData(以名字字典鍵「名稱「和」用戶名「)。

來自OAuth2Client.class的代碼 ... string id = userData [「id」]; 字符串名稱;

 // Some oAuth providers do not return value for the 'username' attribute. 
     // In that case, try the 'name' attribute. If it's still unavailable, fall back to 'id' 
     if (!userData.TryGetValue("username", out name) && !userData.TryGetValue("name", out name)) { 
      name = id; 
     } 

...

正如你可以看到,如果這些關鍵之一是缺少代碼將失敗。