azure - 使用 OAuth2 作为 Azure Appservice 运行 asp.net core 2 应用程序会导致 502 错误

标签 azure asp.net-core oauth-2.0 azure-web-app-service

我使用 Google 的 OAuth 身份验证创建了一个简单的 ASP.NET Core Web 应用程序。我的本地机器上运行得很好。 然而,将其作为 AppService 部署到 Azure 后,OAuth 重定向似乎变得困惑。

应用程序本身可以在这里找到:
https://gcalworkshiftui20180322114905.azurewebsites.net/

这是一个实际返回结果并显示应用程序正在运行的网址:
https://gcalworkshiftui20180322114905.azurewebsites.net/Account/Login?ReturnUrl=%2F

有时应用程序响应良好,但一旦我尝试使用 Google 登录,它就会永远加载并最终返回以下消息:

The specified CGI application encountered an error and the server terminated the process.

在幕后,身份验证回调似乎因 502.3 错误而失败:

502.3 Bad Gateway “The operation timed out”

错误跟踪可以在这里找到: https://gcalworkshiftui20180322114905.azurewebsites.net/errorlog.xml

微软的文档还没有真正帮助。
https://learn.microsoft.com/en-us/azure/app-service/app-service-authentication-overview

进一步的调查使我相信这与以下代码有关:

public GCalService(string clientId, string secret)
{
    string credPath = System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal);
    credPath = Path.Combine(credPath, ".credentials/calendar-dotnet-quickstart.json");

    var credential = GoogleWebAuthorizationBroker.AuthorizeAsync(
        new ClientSecrets
        {
            ClientId = clientId,
            ClientSecret = secret
        },
        new[] {CalendarService.Scope.Calendar},
        "user",
        CancellationToken.None,
        new FileDataStore(credPath, true)).Result;

    // Create Google Calendar API service.
    _service = new CalendarService(new BaseClientService.Initializer()
    {
        HttpClientInitializer = credential,
        ApplicationName = "gcalworkshift"
    });
}

我可以想象 Azure 不支持个人文件夹?谷歌搜索并没有告诉我太多信息。

最佳答案

我关注了Facebook, Google, and external provider authentication in ASP.NET CoreGoogle external login setup in ASP.NET Core创建一个带有 Google 身份验证的 ASP.NET Core Web 应用程序来检查此问题。

我也关注了.NET console application to access the Google Calendar APICalendar.ASP.NET.MVC5构建我的示例项目。核心代码如下,大家可以引用一下:

Startup.cs

    public class Startup
    {
        public readonly IDataStore dataStore = new FileDataStore(GoogleWebAuthorizationBroker.Folder); //C:\Users\{username}\AppData\Roaming\Google.Apis.Auth
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddDbContext<ApplicationDbContext>(options =>
                options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));

            services.AddIdentity<ApplicationUser, IdentityRole>()
                .AddEntityFrameworkStores<ApplicationDbContext>()
                .AddDefaultTokenProviders();

            services.AddAuthentication().AddGoogle(googleOptions =>
            {
                googleOptions.ClientId = "{ClientId}";
                googleOptions.ClientSecret = "{ClientSecret}";
                googleOptions.Scope.Add(CalendarService.Scope.CalendarReadonly); //"https://www.googleapis.com/auth/calendar.readonly"
                googleOptions.AccessType = "offline"; //request a refresh_token
                googleOptions.Events = new OAuthEvents()
                {
                    OnCreatingTicket = async (context) =>
                    {
                        var userEmail = context.Identity.FindFirst(ClaimTypes.Email).Value;

                        var tokenResponse = new TokenResponse()
                        {
                            AccessToken = context.AccessToken,
                            RefreshToken = context.RefreshToken,
                            ExpiresInSeconds = (long)context.ExpiresIn.Value.TotalSeconds,
                            IssuedUtc = DateTime.UtcNow
                        };

                        await dataStore.StoreAsync(userEmail, tokenResponse);
                    }
                };
            });

            services.AddMvc();
        }

    }
}

CalendarController.cs

    [Authorize]
    public class CalendarController : Controller
    {

        private readonly IDataStore dataStore = new FileDataStore(GoogleWebAuthorizationBroker.Folder);

        private async Task<UserCredential> GetCredentialForApiAsync()
        {
            var initializer = new GoogleAuthorizationCodeFlow.Initializer
            {
                ClientSecrets = new ClientSecrets
                {
                    ClientId = "{ClientId}",
                    ClientSecret = "{ClientSecret}",
                },
                Scopes = new[] {
                    "openid",
                    "email",
                    CalendarService.Scope.CalendarReadonly
                }
            };
            var flow = new GoogleAuthorizationCodeFlow(initializer);

            string userEmail = ((ClaimsIdentity)HttpContext.User.Identity).FindFirst(ClaimTypes.Name).Value;

            var token = await dataStore.GetAsync<TokenResponse>(userEmail);
            return new UserCredential(flow, userEmail, token);
        }

        // GET: /Calendar/ListCalendars
        public async Task<ActionResult> ListCalendars()
        {
            const int MaxEventsPerCalendar = 20;
            const int MaxEventsOverall = 50;

            var credential = await GetCredentialForApiAsync();

            var initializer = new BaseClientService.Initializer()
            {
                HttpClientInitializer = credential,
                ApplicationName = "ASP.NET Core Google Calendar Sample",
            };
            var service = new CalendarService(initializer);

            // Fetch the list of calendars.
            var calendars = await service.CalendarList.List().ExecuteAsync();

            return Json(calendars.Items);
        }
    }    

在部署到 Azure Web 应用程序之前,我更改了 folder用于构造 FileDataStore 的参数至D:\home ,但出现以下错误:

UnauthorizedAccessException: Access to the path 'D:\home\Google.Apis.Auth.OAuth2.Responses.TokenResponse-{user-identifier}' is denied.

然后,我尝试设置参数folderD:\home\site并重新部署我的 Web 应用程序,发现它可以按预期工作,并且记录的用户凭据将保存在 D:\home\site 下您的 Azure Web 应用服务器。

enter image description here

Azure Web Apps 在称为沙箱的安全环境中运行,该环境有一些限制,您可以关注详细信息 Azure Web App sandbox

此外,您提到了 App Service Authentication它提供内置身份验证,无需在代码中添加任何代码。由于您已在 Web 应用程序中编写了用于身份验证的代码,因此无需设置应用服务身份验证。

要使用应用服务身份验证,您可以按照 here对于配置,那么您的 NetCore 后端可以通过 access_token 上的 HTTP GET 获取其他用户详细信息( refresh_token/.auth/me 等)。端点,详细信息您可以遵循类似的 issue 。检索到登录用户的 token 响应后,您可以手动构造 UserCredential ,然后构建CalendarService .

关于azure - 使用 OAuth2 作为 Azure Appservice 运行 asp.net core 2 应用程序会导致 502 错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49572563/

相关文章:

java - Google 端点 - Android GoogleAuthIOException Tic Tac Toe - 删除了 clientIds

java - 无法在部署在azure中的java应用程序中发送电子邮件

azure - Windows Azure 共享访问签名始终给出 : Forbidden 403

batch-file - 使用命令行静默模式安装软件

asp.net-core - 如何告诉 Entity Framework 我的 ID 列是自动递增的(AspNet Core 2.0 + PostgreSQL)?

java - 如何将适用于 Java 的 Google Drive Client Library 与我自己开发的 Web 应用程序 OAUTH 2 框架一起使用?

azure - 如何在 Azure AKS 上的一个入口 Controller 上创建多个负载均衡器 IP 地址

c# - 找不到 HttpContextBase 命名空间

asp.net-core - 如何强制 ASP.NET 5 MVC 项目中的所有请求重定向到根 "/"?

javascript - oauth 2 : Javascript vs. PHP?