Google OAuth在本地运行,但在服务器

时间:2017-06-20 14:50:38

标签: asp.net-mvc asynchronous oauth-2.0 google-oauth google-api-dotnet-client

在本地测试时,我能够进行身份验证。使用Oauth2Service检索帐户创建的基本信息。一旦它上线,用户就能够访问谷歌同意页面,但一旦他们选择了一个帐户(或输入了他们的谷歌凭证),它就会坐在加载屏幕上,直到达到我预定义的超时60秒。

我目前收到以下错误:

  

操作已经超时。

     

描述:执行当前Web请求期间发生了未处理的异常。请查看堆栈跟踪以获取有关错误及其源自代码的位置的更多信息。

     

异常详细信息:System.TimeoutException:操作已超时。

     

来源错误:

     

在执行当前Web请求期间生成了未处理的异常。可以使用下面的异常堆栈跟踪来识别有关异常的起源和位置的信息。

     

堆栈追踪:

     

[TimeoutException:操作已超时。]      System.Web.Mvc.Async。<> c__DisplayClass8.b__4()+189      System.Web.Mvc.Async.TaskAsyncActionDescriptor.EndExecute(IAsyncResult asyncResult)+427      System.Web.Mvc.Async。<> c__DisplayClass37.b__36(IAsyncResult asyncResult)+23      System.Web.Mvc.Async.AsyncInvocationWithFilters.b__3d()+112      System.Web.Mvc.Async。<> c__DisplayClass46.b__3f()+ 452      System.Web.Mvc.Async。<> c__DisplayClass46.b__3f()+ 452      System.Web.Mvc.Async。<> c__DisplayClass46.b__3f()+ 452      System.Web.Mvc.Async。<> c__DisplayClass33.b__32(IAsyncResult asyncResult)+15      System.Web.Mvc.Async。<> c__DisplayClass2b.b__1c()+37      System.Web.Mvc.Async。<> c__DisplayClass21.b__1e(IAsyncResult asyncResult)+241      System.Web.Mvc.Controller.b__1d(IAsyncResult asyncResult,ExecuteCoreState innerState)+29      System.Web.Mvc.Async.WrappedAsyncVoid 1.CallEndDelegate(IAsyncResult asyncResult) +111 System.Web.Mvc.Controller.EndExecuteCore(IAsyncResult asyncResult) +53 System.Web.Mvc.Async.WrappedAsyncVoid 1.CallEndDelegate(IAsyncResult asyncResult)+19      System.Web.Mvc.MvcHandler.b__5(IAsyncResult asyncResult,ProcessRequestState innerState)+51      System.Web.Mvc.Async.WrappedAsyncVoid`1.CallEndDelegate(IAsyncResult asyncResult)+111      System.Web.CallHandlerExecutionStep.OnAsyncHandlerCompletion(IAsyncResult ar)+282

我能够缩小它在这条线上的位置:

var token = await Flow.ExchangeCodeForTokenAsync(UserId, authorizationCode.Code, returnUrl,
            taskCancellationToken).ConfigureAwait(false);

对于Context,这里是包含类:

[AuthorizationCodeActionFilter]
public class AuthCallbackController : Google.Apis.Auth.OAuth2.Mvc.Controllers.AuthCallbackController
{
    protected new IAuthorizationCodeFlow Flow { get { return FlowData.Flow; } }

    protected new string UserId
    { get { return FlowData.GetUserId(this); } }

    [AsyncTimeout(60000)]
    public async override Task<ActionResult> IndexAsync(AuthorizationCodeResponseUrl authorizationCode,
        CancellationToken taskCancellationToken)
    {

        if (string.IsNullOrWhiteSpace(authorizationCode.Code))
        {
            var errorResponse = new TokenErrorResponse(authorizationCode);
            return OnTokenError(errorResponse);
        }

        var returnUrl = Request.Url.ToString();
        returnUrl = returnUrl.Substring(0, returnUrl.IndexOf("?"));

        var token = await Flow.ExchangeCodeForTokenAsync(UserId, authorizationCode.Code, returnUrl,
            taskCancellationToken).ConfigureAwait(false);

        var oauthState = await AuthWebUtility.ExtracRedirectFromState(Flow.DataStore, UserId,
            authorizationCode.State).ConfigureAwait(false);

        return new RedirectResult(oauthState);

    }

    protected override FlowMetadata FlowData
    {
        get { return new GoogleFlowMetaData(); }
    }

    protected override ActionResult OnTokenError(TokenErrorResponse errorResponse)
    {
        throw new TokenResponseException(errorResponse);
    }
}

对于其他上下文,这是我的FlowMetaData实现:

public class GoogleFlowMetaData : FlowMetadata
{
    public static readonly IAuthorizationCodeFlow flow =
        new ForceOfflineGoogleAuthorizationCodeFLow(new GoogleAuthorizationCodeFlow.Initializer
        {
            ClientSecrets = new ClientSecrets
            {
                ClientId = ConfigurationManager.AppSettings["Google.ClientID"],
                ClientSecret = ConfigurationManager.AppSettings["Google.ClientSecret"]
            },
            Scopes = new[] {
                Scope.UserinfoProfile,
                Scope.UserinfoEmail
            },
            DataStore = new GoogleDataStore(new DBContext())
        });

    public override string GetUserId(Controller controller)
    {
        var user = controller.User.Identity;
        if (controller.User.Identity.IsAuthenticated)
        {
            return controller.User.Identity.GetUserId();
        }
        var userId = (string)controller.Session["google_userId"];
        if (string.IsNullOrWhiteSpace(userId))
        {
            userId = Guid.NewGuid().ToString();
            controller.Session["google_userId"] = userId;
        }
        return userId;
    }

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

    internal class ForceOfflineGoogleAuthorizationCodeFLow : GoogleAuthorizationCodeFlow
    {
        public ForceOfflineGoogleAuthorizationCodeFLow(GoogleAuthorizationCodeFlow.Initializer initializer)
            : base(initializer)
        {

        }

        public override AuthorizationCodeRequestUrl CreateAuthorizationCodeRequest(string redirectUri)
        {
            var ss = new GoogleAuthorizationCodeRequestUrl(new Uri(AuthorizationServerUrl));
            ss.AccessType = "offline";
            ss.ApprovalPrompt = "force";
            ss.ClientId = ClientSecrets.ClientId;
            ss.Scope = string.Join(" ", Scopes);
            ss.RedirectUri = redirectUri;
            return ss;
        }
    }
}

使用的Nuget包:

  • Google.Apis
  • Google.Apis.Auth
  • Google.Apis.Auth.Mvc
  • Google.Apis.Core
  • Google.Apis.Oauth2.v2

其他注意事项:

  • 在Windows Web Server 2008(IIS 7)上托管
  • 作为子域名托管
  • 我是子域名/域名
  • 的经过验证的所有者
  • 子域名具有SSL
  • 子域名&amp;域名已添加到项目的Google API管理器上的“允许的域名”列表中
  • 为Google API管理器中的OAuth客户端ID设置了重定向网址
  • 已验证ClientID&amp; API Manager与&之间的ClientSecret匹配;应用
  • Token storage in database is setup and working
  • 隐私政策已在OAuth客户端
  • 中设置
  • Server's system clock is valid.

有关如何解决此问题的任何建议或想法? 如果有任何其他信息有帮助,请告知我们。

1 个答案:

答案 0 :(得分:1)

将解决方案迁移到Azure,而不是将其托管在我自己的服务器上,并解决了问题。