首页 > 解决方案 > .Net Core Identity 外部登录不起作用

问题描述

我有一个为谷歌设置了外部登录的网站。我已经成功地让它在开发中工作,但是当我转向生产时,它却失败了。当我单击该按钮时,它并没有将我发送到 Google 的 account.google.com 页面,而是将我发送到/Identity/Account/ExternalLogins错误代码为HTTP ERROR 400. 生产和环境之间的按钮是相同的。除了电子邮件发送部分,一切都与脚手架期间生成的相同。我的生产环境使用 Ubuntu 和 Nginx。这可能是什么原因造成的?我无法在生产之外重现该问题。

顺便说一句,这是默认按钮:

<form id="external-account" asp-page="./ExternalLogin" asp-route-returnUrl="@Model.ReturnUrl" method="post" class="form-horizontal">
    <button type="submit" class="btn btn-primary" name="provider" value="@provider.Name" 
          title="Log in using your @provider.DisplayName account">@provider.DisplayName
    </button>
</form>

我的按钮是更改的默认谷歌登录按钮,但它在开发中有效,所以我认为这并不重要:

<form id="external-account" asp-page="./ExternalLogin" asp-route-returnUrl="@Model.ReturnUrl" method="post" class="form-horizontal">
    <div class="g-signin2" style="border:inherit;" data-onsuccess="onSuccess" data-gapiscan="true" data-onload="true">
        <div style="height:36px;width:120px;" class="abcRioButton abcRioButtonLightBlue">
            <button class="abcRioButtonContentWrapper" style="border:inherit; background-color:white !important"
                    type="submit" name="provider" value="@provider.Name" title="Log in using your @provider.DisplayName account">
                <img class="position-absolute" src="https://assets.stickpng.com/images/5847f9cbcef1014c0b5e48c8.png" style="left: 12px;height: 18px;bottom: 10px;">
                <span style="font-size:13px;line-height:34px;" class="abcRioButtonContents">
                    <span class="ml-3">Sign in</span>
                </span>
            </button>
        </div>
    </div>
</form>

以下是我的相关部分,为简洁起见Startup.cs,删除了一些内容ConfigureServices()

public void ConfigureServices(IServiceCollection services)
        {
            services.AddDbContext<ApplicationDbContext>(options =>
                options.UseMySql(Configuration.GetConnectionString("UserDB"), MySqlOptions => MySqlOptions
                .ServerVersion(new Version(8, 0, 22), ServerType.MySql)));

            services.AddIdentity<ApplicationUser, ApplicationRole>()
                .AddEntityFrameworkStores<ApplicationDbContext>()
                .AddDefaultUI()
                .AddDefaultTokenProviders();
            services.Configure<IdentityOptions>(options =>
            {
                options.SignIn.RequireConfirmedAccount = true;
                options.User.RequireUniqueEmail = true;
                options.User.AllowedUserNameCharacters =
                        "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._";
                options.Password.RequireNonAlphanumeric = true;
                options.Password.RequireDigit = true;
                options.Password.RequireLowercase = true;
                options.Password.RequireUppercase = true;
                options.Password.RequiredLength = 8;
            });


            services.AddAuthentication()
                .AddGoogle(options =>
            {
                IConfigurationSection googleAuthNSection =
                    Configuration.GetSection("Authentication:Google");

                options.ClientId = googleAuthNSection["ClientId"];
                options.ClientSecret = googleAuthNSection["ClientSecret"];
            });

            services.AddServerSideBlazor();
            services.AddScoped<AuthenticationStateProvider, RevalidatingIdentityAuthenticationStateProvider<ApplicationUser>>();
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            
            ConnectionString = Configuration["ConnectionStrings:DataDB"];

            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
                app.UseDatabaseErrorPage();
                app.UseBrowserLink();
            }
            else
            {               
                app.UseExceptionHandler("/Error");
                // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
                app.UseHsts();
            }
            app.UseHeadElementServerPrerendering();

            app.UseHttpsRedirection();
            app.UseStaticFiles();

            app.UseRouting();

            app.UseAuthentication();
            app.UseAuthorization();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
                endpoints.MapBlazorHub();
                endpoints.MapFallbackToPage("/_Host");
            });
        }

经过更多调查并将日志记录设置为跟踪后,我发现了以下错误:

连接 ID“0HM5SB235ONN8”错误请求数据:“带有‘连接:升级’的请求不能在请求正文中包含内容。”

我认为是因为我的sites-enabled/default文件,我必须根据官方 Blazor 部署文档以这种方式配置:

        location / {
                # First attempt to serve request as file, then
                # as directory, then fall back to displaying a 404.
                proxy_pass http://localhost:5000;
                proxy_http_version 1.1;
                proxy_set_header Upgrade $http_upgrade;
                proxy_set_header Connection "upgrade";
                proxy_set_header Connection $http_connection;
                proxy_set_header Host $host;
                proxy_cache_bypass $http_upgrade;
        }

标签: asp.net-corenginxasp.net-identity

解决方案


问题出在我的 nginx 文件中,我错误地将其设置为托管。我将其更改为以下内容并且有效:

map $http_connection $connection_upgrade {
     "~*Upgrade" $http_connection;
    default keep-alive;
}

server {
    root /var/www/html;

    # Add index.php to the list if you are using PHP
    index index.html;
        server_name domain.us;


    location / {
        proxy_pass         http://localhost:5000;
        proxy_http_version 1.1;
        proxy_set_header   Upgrade $http_upgrade;
        proxy_set_header   Connection $connection_upgrade;
        proxy_set_header   Host $host;
        proxy_cache_bypass $http_upgrade;
        proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header   X-Forwarded-Proto $scheme;
    }
}

然后我改变了我Startup.cs的包括:

if (string.Equals(
            Environment.GetEnvironmentVariable("ASPNETCORE_FORWARDEDHEADERS_ENABLED"),
            "true", StringComparison.OrdinalIgnoreCase))
            {
                services.Configure<ForwardedHeadersOptions>(options =>
                {
                    options.ForwardedHeaders = ForwardedHeaders.XForwardedFor |
                        ForwardedHeaders.XForwardedProto;
                    // Only loopback proxies are allowed by default.
                    // Clear that restriction because forwarders are enabled by explicit 
                    // configuration.
                    options.KnownNetworks.Clear();
                    options.KnownProxies.Clear();
                });
            }
//#################
 app.UseForwardedHeaders();
 app.UseCookiePolicy(new CookiePolicyOptions(){
    MinimumSameSitePolicy = SameSiteMode.Lax
 });
 app.UseCertificateForwarding();

推荐阅读