【问题标题】:GoogleWebAuthorizationBroker failed to launch browser with https //accounts.google.com/o/oauth2/v2/auth; redirect uri mismatchGoogleWebAuthorizationBroker 无法使用 https //accounts.google.com/o/oauth2/v2/auth 启动浏览器;重定向 uri 不匹配
【发布时间】:2018-06-12 10:22:38
【问题描述】:

我有与这个问题完全相同的问题: How do I set return_uri for GoogleWebAuthorizationBroker.AuthorizeAsync?

但是,这个问题是 3 年前回答的,而提供的答案对我不起作用;我看不到实际设置重定向 uri 的方法。那么问题来了:

static async Task<UserCredential> GetCredential()
{

    var clientSecretPath = HttpRuntime.AppDomainAppPath + "client_secret.json";
    var credPath = HttpRuntime.AppDomainAppPath + "credentials/GoogleAnalyticsApiConsole/";

    UserCredential credential;

    using (var stream = new FileStream(clientSecretPath,
            FileMode.Open, FileAccess.Read))
    {
        var secrets = GoogleClientSecrets.Load(stream).Secrets;


        credential = await GoogleWebAuthorizationBroker.AuthorizeAsync(
            secrets,
            new[] {AnalyticsReportingService.Scope.Analytics},
            "analytics@mysite.com", 
            CancellationToken.None, 
            new FileDataStore(credPath, true));

        return credential;
    }
}

这将返回以下错误:

failed to launch browser with https //accounts.google.com/o/oauth2/v2/auth

它正在尝试使用 redirect_uri = "http://localhost:/authorize" 启动 oauth2 页面;当我尝试直接查看它尝试启动的 url 时,页面显示“请求中的重定向 URI:http://localhost:XXXXX/authorize/ 与注册的重定向 URI 不匹配”

我尝试将 localhost:XXXXX 添加到 Google API 控制台中的授权 url,但下次我运行它时端口不同,例如 localhost:XXXYY。我的 client_secret.json 文件列出了所有授权的重定向 url,但没有被使用。如何设置重定向 uri 并解决此问题?

【问题讨论】:

    标签: c# asp.net oauth google-api google-analytics-api


    【解决方案1】:

    我不确定您是在尝试构建本地安装的应用程序还是 asp.net Web 应用程序,但根据您指出的问题,我假设它是一个 Web 应用程序,这就是我解决它的方法。

    首先,GoogleWebAuthorizationBroker 的默认实现是针对本地安装的应用程序。你可以在这个link 中找到它的实现 .因此,您的代码可能在您的本地机器上运行良好,但当托管在网络服务器中时,它可能会永远加载。

    因此,您需要为 google 文档中提到的 Web 应用程序实现自己的 AuthorizationCodeFlow。

    这就是我在 ASP.NET Core MVC Web 应用程序中实现它的方式

    public async Task<IActionResult> ConfigureGA(CancellationToken cancellationToken)
            {
                GoogleAnalyticsModel model = new GoogleAnalyticsModel();
                var state = UriHelper.GetDisplayUrl(Request);
                var result = await GetCredential(state, cancellationToken);
                if (result.Credential != null)
                {
                    using (var svc = new AnalyticsService(
                        new BaseClientService.Initializer
                        {
                            HttpClientInitializer = result.Credential,
                            ApplicationName = "Your App Name"
                        }))
                    {
    
                        ManagementResource.AccountSummariesResource.ListRequest list = svc.Management.AccountSummaries.List();
                        list.MaxResults = 1000;
                        AccountSummaries feed = await list.ExecuteAsync();
                        model.UserAccounts = feed.Items.ToList();
                    }
    
                    return View(model);
                }
                else
                {
                    return new RedirectResult(result.RedirectUri);
                }
    
            }    
    private async Task<AuthorizationCodeWebApp.AuthResult> GetCredential(string state, CancellationToken cancellationToken)
            {
                var userId = userManager.GetUserAsync(User).Result.Id;
                var redirectUri = Request.Scheme + "://" + Request.Host.ToUriComponent() + "/authcallback/";
                using (var stream = new FileStream("client_secret.json",
                     FileMode.Open, FileAccess.Read))
                {
                    IAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow(new GoogleAuthorizationCodeFlow.Initializer
                    {
                        ClientSecrets = GoogleClientSecrets.Load(stream).Secrets,
                        Scopes = new[] { AnalyticsService.Scope.AnalyticsReadonly, AnalyticsReportingService.Scope.AnalyticsReadonly },
                        DataStore = datastore
                    });
    
                    return await new AuthorizationCodeWebApp(flow, redirectUri, state)
                            .AuthorizeAsync(userId, cancellationToken);
                }
            }
    

    我在请求 oauth 凭据(即 GetCredential() 方法)时传递了应用程序的状态。

    在此方法中,创建您自己的 IAuthorizationCodeFlow 并将您的流程、redirect_uri(您还必须在 Google 开发者控制台中设置)和应用程序的状态传递给 AuthorizationCodeWebApp

    接下来您必须实现 authcallback 控制器来处理 oauth 代码。此代码类似于 google-dotnet-client 库 found here,但我采用了相同的代码,因为我正在使用 Microsoft.AspNetCore.Mvc

    public class AuthCallbackController : Controller
        {
            private readonly UserManager<ApplicationUser> userManager;
            private readonly IGoogleAnalyticsDataStore datastore;
    
            public AuthCallbackController(UserManager<ApplicationUser> userManager, IGoogleAnalyticsDataStore datastore)
            {
                this.userManager = userManager;
                this.datastore = datastore;
            }
    
            protected virtual ActionResult OnTokenError(TokenErrorResponse errorResponse)
            {
                throw new TokenResponseException(errorResponse);
            }
            public async virtual Task<ActionResult> Index(AuthorizationCodeResponseUrl authorizationCode,
                CancellationToken taskCancellationToken)
            {
                using (var stream = new FileStream("client_secret.json",
                     FileMode.Open, FileAccess.Read))
                {
                    IAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow(
            new GoogleAuthorizationCodeFlow.Initializer
            {
                ClientSecrets = GoogleClientSecrets.Load(stream).Secrets,
                DataStore = datastore,
                Scopes = new[] { AnalyticsService.Scope.AnalyticsReadonly, AnalyticsReportingService.Scope.AnalyticsReadonly }
            });
    
                    if (string.IsNullOrEmpty(authorizationCode.Code))
                    {
                        var errorResponse = new TokenErrorResponse(authorizationCode);
    
                        return OnTokenError(errorResponse);
                    }
                    string userId = userManager.GetUserAsync(User).Result.Id;
                    var returnUrl = UriHelper.GetDisplayUrl(Request);
    
                    var token = await flow.ExchangeCodeForTokenAsync(userId, authorizationCode.Code, returnUrl.Substring(0, returnUrl.IndexOf("?")),
                        taskCancellationToken).ConfigureAwait(false);
    
                    // Extract the right state.
                    var oauthState = await AuthWebUtility.ExtracRedirectFromState(datastore, userId,
                        authorizationCode.State).ConfigureAwait(false);
    
                    return new RedirectResult(oauthState);
                }
            }
        }
    

    希望这能回答您的问题,并且超出了问题的范围。

    【讨论】:

      【解决方案2】:

      我今天也遇到了同样的问题。 原来,没有设置“默认”程序来处理 http/https 协议。

      【讨论】:

        猜你喜欢
        • 2020-10-12
        • 1970-01-01
        • 2014-10-07
        • 1970-01-01
        • 1970-01-01
        • 2019-08-03
        • 1970-01-01
        • 1970-01-01
        • 2015-07-12
        相关资源
        最近更新 更多