2017-08-16 139 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并发布表单数据,但这应该是非常简单的。