2017-08-16 143 views
0

我一直在試圖遵循一些教程,我可以找到一個mvc應用程序允許用戶對應用程序進行身份驗證並獲取訪問和刷新標記。不幸的是,我找不到足夠清楚的地方,以便我可以跟蹤正在發生的事情。我從谷歌的sample code開始,然後發現其他一些像this onethis one使用mvc從google api獲取訪問令牌的困惑

當我運行我的應用程序時,我試着去http://localhost:61581/Integration/Google/IndexAsync它碰到了那個方法,最終碰到了AppFlowMetadata.GetUserId方法,然後碰到了我自定義的TenixDataStore類的GetAsync方法。

易混淆的東西是

  1. 首先,我該怎麼正確的URL /方法?我想我是基於谷歌的代碼示例,但不知道。
  2. 我以爲我會得到的關鍵是電子郵件地址,而不是一個GUID。這是谷歌如何識別用戶?
  3. 如果我要去正確的網址,爲什麼網頁只是掛起,永遠不會返回。我預計它會打開一個沒有發生的谷歌授權頁面。

這是我的代碼。

AppFlowMetadata類

using System.Web.Mvc; 
using Google.Apis.Auth.OAuth2; 
using Google.Apis.Auth.OAuth2.Flows; 
using Google.Apis.Auth.OAuth2.Mvc; 
using Google.Apis.Gmail.v1; 
using Tenix.Domain.Constants; 

namespace MyApp.Areas.Integration.Controllers 
{ 
    public class AppFlowMetadata : FlowMetadata 
    { 
     private static readonly IAuthorizationCodeFlow flow = 
      new GoogleAuthorizationCodeFlow(new GoogleAuthorizationCodeFlow.Initializer 
      { 
       ClientSecrets = new ClientSecrets 
       { 
        ClientId = APIConstants.GMailApiKey, 
        ClientSecret = APIConstants.GmailApiSecret 
       }, 
       Scopes = new[] {GmailService.Scope.GmailReadonly}, 
       DataStore = new TenixDataStore() 
      }); 

     public override IAuthorizationCodeFlow Flow 
     { 
      get { return flow; } 
     } 

     public override string GetUserId(Controller controller) 
     { 
      // In this sample we use the session to store the user identifiers. 
      // That's not the best practice, because you should have a logic to identify 
      // a user. You might want to use "OpenID Connect". 
      // You can read more about the protocol in the following link: 
      // https://developers.google.com/accounts/docs/OAuth2Login. 
      var user = controller.Session["UserID"]; 
      if (user == null) return null; 
      return user.ToString(); 
     } 
    } 
} 

GoogleController

using System.Threading; 
using System.Threading.Tasks; 
using System.Web.Mvc; 
using Google.Apis.Auth.OAuth2.Mvc; 
using Google.Apis.Gmail.v1; 
using Google.Apis.Services; 

namespace MyApp.Areas.Integration.Controllers 
{ 
    public class GoogleController : Controller 
    { 
     public async Task IndexAsync(CancellationToken cancellationToken) 
     { 
      if (Session["UserID"] == null) 
      { 
       Response.Redirect("~/Login.aspx", true); 
      } 

      var result = await new AuthorizationCodeMvcApp(this, new AppFlowMetadata()).AuthorizeAsync(cancellationToken); 

      if (result.Credential != null) 
      { 
       var service = new GmailService(new BaseClientService.Initializer 
       { 
        HttpClientInitializer = result.Credential, 
        ApplicationName = "Tenix Gmail Integration" 
       }); 
      } 
     } 
    } 
} 

TenixDataStore類

using System; 
using System.Threading.Tasks; 
using DataBaseUtilitiesTEN; 
using Google.Apis.Json; 
using Google.Apis.Util.Store; 
using Newtonsoft.Json.Linq; 
using Synergy.Extensions; 
using Tenix.Domain.Data.Respositories; 
using Tenix.Domain.Model.Integration; 
using Tenix.Domain.Services; 

namespace MyApp.Areas.Integration.Controllers 
{ 
    public class TenixDataStore : IDataStore 
    { 
     private readonly string conStr = ConnectionStrings.GeneralInfo; 
     private CredentialService _service; 

     public TenixDataStore() 
     { 
      _service = new CredentialService(new CredentialRepository(conStr)); 
     } 

     public Task StoreAsync<T>(string key, T value) 
     { 
      if (string.IsNullOrEmpty(key)) 
       throw new ArgumentException("Key MUST have a value"); 

      var serialized = NewtonsoftJsonSerializer.Instance.Serialize(value); 
      var jObject = JObject.Parse(serialized); 

      var access_token = jObject.SelectToken("access_token"); 
      var refresh_token = jObject.SelectToken("refresh_token"); 

      if (access_token == null) 
       throw new ArgumentException("Missing access token"); 

      if (refresh_token == null) 
       throw new ArgumentException("Missing refresh token"); 

      _service.SaveUserCredentials(new UserCredential 
      { 
       EmailAddress = key, 
       AccessToken = (string)access_token, 
       RefreshToken = (string)refresh_token 
      }); 

      return Task.Delay(0); 
     } 

     public Task DeleteAsync<T>(string key) 
     { 
      _service.DeleteCredentials(key); 
      return Task.Delay(0); 
     } 

     public Task<T> GetAsync<T>(string userId) 
     { 
      var credentials = _service.GetUserCredentials(userId.To<int>()); 
      var completionSource = new TaskCompletionSource<T>(); 

      if (!string.IsNullOrEmpty(credentials.AccessToken)) 
       completionSource.SetResult(NewtonsoftJsonSerializer.Instance.Deserialize<T>(credentials.AccessToken)); 

      return completionSource.Task; 
     } 

     public Task ClearAsync() 
     { 
      return Task.Delay(0); 
     } 
    } 
} 

AuthCallbackController

using Google.Apis.Auth.OAuth2.Mvc; 

namespace MyApp.Areas.Integration.Controllers 
{ 
    public class AuthCallbackController : Google.Apis.Auth.OAuth2.Mvc.Controllers.AuthCallbackController 
    { 
     protected override FlowMetadata FlowData 
     { 
      get { return new AppFlowMetadata(); } 
     } 
    } 
} 

回答

0

花了幾天的時間試圖弄清楚這一點,並沒有任何與谷歌api.net圖書館取得任何進展我最終只是與我自己的實施,reading their documentation至少是我可以完全理解的東西。如果任何人可以使用代碼,這就是我最終的結果。仍然需要做一些重構,但在這一點上它正在工作。

只需確保AuthorizeResponse和Authorize路由被註冊爲授權重定向uris。

public class GoogleController : Controller 
{ 
    private readonly CredentialService _credentialService; 
    private readonly GoogleEndpoints _endpoints; 

    public GoogleController() 
    { 
     _endpoints = new GoogleEndpoints(); 
     _credentialService = new CredentialService(new CredentialRepository(ConnectionStrings.GeneralInfo)); 
    } 

    private string AuthorizeUrl 
    { 
     get 
     { 
      return "/Integration/Google/Authorize"; 
     } 
    } 

    private string AuthorizeResponseUrl 
    { 
     get 
     { 
      return "/Integration/Google/AuthorizeResponse"; 
     } 
    } 

    private string SaveResponseUrl 
    { 
     get 
     { 
      return "/Integration/Google/SaveResponse"; 
     } 
    } 

    public void Authorize() 
    { 
     if (Session["UserID"] == null || Session["Email"] == null) 
     { 
      Response.Redirect("~/Login.aspx", true); 
      Session["LoginSource"] = AuthorizeUrl; 
      Response.End(); 
     } 
     else 
     { 
      if (Session["SessionId"] == null || Session["SessionId"].ToString().Trim().Length == 0) 
       Session["SessionId"] = _credentialService.CreateSessionId(Session["UserID"].To<int>()); 

      var url = _endpoints.AuthorizationEndpoint + "?" + 
         "client_id=" + APIConstants.GMailApiKey + "&" + 
         "response_type=code&" + 
         "scope=openid%20email&" + 
         "redirect_uri=" + AuthorizeResponseUrl + "&" + 
         "state=" + Session["SessionId"] + "&" + 
         "login_hint=" + Session["Email"] + "&" + 
         "access_type=offline"; 

      Response.Redirect(url); 
     } 
    } 

    public ActionResult AuthorizeResponse() 
    { 
     var state = Request.QueryString["state"]; 
     if (state == Session["SessionId"].ToString()) 
     { 
      var code = Request.QueryString["code"]; 
      var values = new Dictionary<string, object> 
      { 
       {"code", code}, 
       {"redirect_uri", AuthorizeResponseUrl}, 
       {"client_id", APIConstants.GMailApiKey}, 
       {"client_secret", APIConstants.GmailApiSecret}, 
       {"grant_type", "authorization_code"}, 
       {"scope", ""} 
      }; 

      var webmethods = new WebMethods(); 
      var tokenResponse = webmethods.Post(_endpoints.TokenEndpoint, values); 

      var jobject = JObject.Parse(tokenResponse); 
      var access_token = jobject.SelectToken("access_token"); 
      var refresh_token = jobject.SelectToken("refresh_token"); 

      if (access_token == null || access_token.ToString().Trim().Length == 0) 
      { 
       //notify devs something went wrong 
       return View(new GoogleAuthResponse(tokenResponse, false)); 
      } 

      var credentials = _credentialService.GetUserCredentials(Session["SessionId"].ToString()); 

      credentials.AccessToken = access_token.ToString(); 
      credentials.RefreshToken = refresh_token.ToString(); 
      credentials.EmployeeId = Session["UserId"].To<int>(); 

      _credentialService.SaveUserCredentials(credentials); 

      return View(new GoogleAuthResponse("Integration successful!", true)); 
     } 

     return View(new GoogleAuthResponse("Missing state information.", false)); 
    } 
} 

而助手類獲得谷歌端點。

public class GoogleEndpoints 
{ 
    public GoogleEndpoints() 
    { 
     using (var client = new WebClient()) 
     { 
      var response = client.DownloadString("https://accounts.google.com/.well-known/openid-configuration"); 
      var jobject = JObject.Parse(response); 
      AuthorizationEndpoint = jobject.SelectToken("authorization_endpoint").ToString(); 
      TokenEndpoint = jobject.SelectToken("token_endpoint").ToString(); 
     } 
    } 

    public string AuthorizationEndpoint { get; private set; } 

    public string TokenEndpoint { get; private set; } 
} 

控制器使用另一對助手類來解析json併發布表單數據,但這應該是非常簡單的。