2012-12-05 17 views
15

DotNetOpenAuthとMVC4を使用してGoogle用のカスタムOAuth2Clientを実装する際に問題が発生しています。OAuth2とDotNetOpenAuth - Googleカスタムクライアントの実装

私は成功し、Googleのエンドポイント https://accounts.google.com/o/oauth2/auth

に承認申請を行うことができますし、ユーザーが自分のアカウントに自分のアプリケーションへのアクセスを許可する場合は、Googleが要求するポイントになってきました。これまでのすべての良い。ユーザーが「OK」をクリックすると、googleはコールバックURLを期待どおりに呼び出します。

私は私が見てきたそれは常にIsSuccessful = falseProvider = ""

でAuthenticationResultを返します

var authenticationResult = OAuthWebSecurity.VerifyAuthentication(Url.Action("ExternalLoginCallback", new { ReturnUrl = returnUrl })); 

(Microsoft.Web.WebPages.OAuth)OAuthWebSecurityクラスにVerifyAuthenticationメソッドを呼び出すときに問題がありますこのコードにOAuthWebSecurityクラスがプロバイダ名を取得しようとします。

Request.QueryString["__provider__"] 

しかし、Googleはこの情報をクエリ文字列に戻していません。私が実装している他のプロバイダ(LinkedIn)はプロバイダ名を送り返しています。すべて正常に動作します。

Microsoft.Web.WebPages.OAuthクラスを放棄し、DotNetOpenAuthを使用せずにこの時点で何ができるか分かりませんが、誰かが別の解決方法を試してくれることを期待していました。

私は広範囲に検索していますが、何か助けになるとは思われません...同じことをやっている人の例を見つけることさえ難しいことが分かりました。

ご迷惑をおかけして申し訳ありません。

+0

私はMSラッパーを使用したことがなく、DotNetOpenAuthを直接書いたことがあり、問題はほとんどありませんでした。それだけではあまり複雑ではなく、たくさんの例があります。 –

+0

不足しているプロバイダ文字列に関するGoogleのバグレポートを提出しますか? – weismat

+0

@PaulTyng - ありがとう、はい - これは私が最後にやったことです。 – soupy1976

答えて

11

更新:https://github.com/mj1856/DotNetOpenAuth.GoogleOAuth2

彼が指摘したよう:唯一のOpenIDでASP.Net MVC 4船のための DNOAとOAuthWebSecurityを、彼はあなたがGitHubのから得ることができたこれに対するソリューションをパッケージ化しているの下にマット・ジョンソンは言及したようGoogleのプロバイダです。これは代わりに使用できるOAuth2クライアントです。

重要 - ASP.Net MVC 5を使用している場合、このパッケージは適用されません。代わりにMicrosoft.Owin.Security.Googleを使用する必要があります。 (また、VS 2013でのMVC 5スターターテンプレートに付属)


は、私はそれが入ってくるときの要求をキャッチし、それが来ているプロバイダを参照するために自分自身のチェックを行うことで、最終的にこのラウンドですから。 Googleでは、 'state'というOAuthリクエストにパラメータを送信できるようにしています。コールバックを行うときに渡すだけなので、Googleのプロバイダ名を渡すために使用しています"__provider__"が存在しません。このような

何か:

public String GetProviderNameFromQueryString(NameValueCollection queryString) 
    { 
     var result = queryString["__provider__"]; 

     if (String.IsNullOrWhiteSpace(result)) 
     { 
      result = queryString["state"]; 
     } 

     return result; 
    } 

私は、グーグルのカスタムOAuth2Clientを実施してきた、と私は手動でマイクロソフトのラッパーものを迂回し、その上で自分自身をVerifyAuthenticationメソッドを呼び出します。

これにより、Microsoftのラッパーを使用している他のプロバイダのための準備が整えました。 1010100 1001010 @によって要求されたよう

、ここではGoogleのための私のカスタムOAuth2Clientである(注:これは、いくつかの片付けをニーズ私はまだCODE UPを片付けTO ROUNDを持っていないことがが働くん!。):

public class GoogleCustomClient : OAuth2Client 
{ 
    ILogger _logger; 

    #region Constants and Fields 

    /// <summary> 
    /// The authorization endpoint. 
    /// </summary> 
    private const string AuthorizationEndpoint = "https://accounts.google.com/o/oauth2/auth"; 

    /// <summary> 
    /// The token endpoint. 
    /// </summary> 
    private const string TokenEndpoint = "https://accounts.google.com/o/oauth2/token"; 

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

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

    #endregion 


    public GoogleCustomClient(string clientId, string clientSecret) 
     : base("Google") 
    { 
     if (string.IsNullOrWhiteSpace(clientId)) throw new ArgumentNullException("clientId"); 
     if (string.IsNullOrWhiteSpace(clientSecret)) throw new ArgumentNullException("clientSecret"); 

     _logger = ObjectFactory.GetInstance<ILogger>(); 

     this._clientId = clientId; 
     this._clientSecret = clientSecret; 
    } 

    protected override Uri GetServiceLoginUrl(Uri returnUrl) 
    { 
     StringBuilder serviceUrl = new StringBuilder(); 

     serviceUrl.AppendFormat("{0}?scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.email+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.profile", AuthorizationEndpoint); 
     serviceUrl.Append("&state=google"); 
     serviceUrl.AppendFormat("&redirect_uri={0}", returnUrl.ToString()); 
     serviceUrl.Append("&response_type=code"); 
     serviceUrl.AppendFormat("&client_id={0}", _clientId); 

     return new Uri(serviceUrl.ToString()); 

    } 

    protected override IDictionary<string, string> GetUserData(string accessToken) 
    { 
     RestClient client = new RestClient("https://www.googleapis.com"); 
     var request = new RestRequest(String.Format("/oauth2/v1/userinfo?access_token={0}", accessToken), Method.GET); 
     IDictionary<String, String> extraData = new Dictionary<String, String>(); 

     var response = client.Execute(request); 
     if (null != response.ErrorException) 
     { 
      return null; 
     } 
     else 
     { 
      try 
      { 
       var json = JObject.Parse(response.Content); 

       string firstName = (string)json["given_name"]; 
       string lastName = (string)json["family_name"]; 
       string emailAddress = (string)json["email"]; 
       string id = (string)json["id"]; 

       extraData = new Dictionary<String, String> 
       { 
        {"accesstoken", accessToken}, 
        {"name", String.Format("{0} {1}", firstName, lastName)}, 
        {"firstname", firstName}, 
        {"lastname", lastName}, 
        {"email", emailAddress}, 
        {"id", id}           
       }; 
      } 
      catch(Exception ex) 
      { 
       _logger.Error("Error requesting OAuth user data from Google", ex); 
       return null; 
      } 
      return extraData; 
     } 

    } 

    protected override string QueryAccessToken(Uri returnUrl, string authorizationCode) 
    { 
     StringBuilder postData = new StringBuilder(); 
     postData.AppendFormat("client_id={0}", this._clientId); 
     postData.AppendFormat("&redirect_uri={0}", HttpUtility.UrlEncode(returnUrl.ToString())); 
     postData.AppendFormat("&client_secret={0}", this._clientSecret); 
     postData.AppendFormat("&grant_type={0}", "authorization_code"); 
     postData.AppendFormat("&code={0}", authorizationCode); 


     string response = ""; 
     string accessToken = ""; 

     var webRequest = (HttpWebRequest)WebRequest.Create(TokenEndpoint); 

     webRequest.Method = "POST"; 
     webRequest.ContentType = "application/x-www-form-urlencoded"; 

     try 
     { 

      using (Stream s = webRequest.GetRequestStream()) 
      { 
       using (StreamWriter sw = new StreamWriter(s)) 
        sw.Write(postData.ToString()); 
      } 

      using (WebResponse webResponse = webRequest.GetResponse()) 
      { 
       using (StreamReader reader = new StreamReader(webResponse.GetResponseStream())) 
       { 
        response = reader.ReadToEnd(); 
       } 
      } 

      var json = JObject.Parse(response); 
      accessToken = (string)json["access_token"]; 
     } 
     catch(Exception ex) 
     { 
      _logger.Error("Error requesting OAuth access token from Google", ex); 
      return null; 
     } 

     return accessToken; 

    } 

    public override AuthenticationResult VerifyAuthentication(HttpContextBase context, Uri returnPageUrl) 
    { 

     string code = context.Request.QueryString["code"]; 
     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["id"]; 
     string name; 

     // 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; 
     } 

     // add the access token to the user data dictionary just in case page developers want to use it 
     userData["accesstoken"] = accessToken; 

     return new AuthenticationResult(
      isSuccessful: true, provider: this.ProviderName, providerUserId: id, userName: name, extraData: userData); 
    } 
+0

ちなみに、カスタムOAuth2Clientの例を見つけるのはかなり難しいですが、誰かが私の実装を見てみたいと思っているのであれば、私は叫ぶだけです。 – soupy1976

+0

これ以外の回答がない場合はこれを正しいとマークします。 – soupy1976

+0

私は遊んできて、うまく動作するようにしています。あなたはうまくいきましたが、コールバックがGoogleのものかどうかを確認してから、Google OAuth2クライアントを手動でチェックすることはできません。私はDNOAコードを見てきました。あなたがそれを登録したときにカスタムGoogleクライアントの 'VerifyAuthentication()'をなぜ呼び出さないのかわかりません( 'OAuthWebSecurity.RegisterClient(...)')それと運がいい? – Brendan

関連する問題