CORS 错误:LinkedIn 身份验证; .NET Core 5 REST API

Posted

技术标签:

【中文标题】CORS 错误:LinkedIn 身份验证; .NET Core 5 REST API【英文标题】:CORS Error: LinkedIn Authentication; .NET Core 5 REST Api 【发布时间】:2021-10-16 03:22:40 【问题描述】:

技术栈

使用 .NET CORE React 模板 1 个 IIS 网站 应用程序池(v4 集成) 80 端口
    单击注册按钮,调用注册组件。 useEffect() 中的组件,使用 Axios 调用“/login URL” C# Map("/login") 被称为使用 LinkedIn 进行身份验证的挑战 然后返回 CORS 错误

错误 Snapshot 1 of 5 Snapshot 2 of 5; Snapshot 3 of 5; Snapshot 4 of 5; Snapshot 5 of 5

反应代码

      const url = `/login`;

      const headers = 
        'Content-Type': 'text/html'
      

      axios(
        method: 'get',
        url: url,
        headers: headers
      )
        .then((response) => ...)
        .catch((error: Error | AxiosError) => ...);

C# 代码 - 链接身份验证、Cookie、CORS 中间件

Start.cs - ConfigureServices()

        public void ConfigureServices(IServiceCollection services)
        
            #region AddAuthentication, AddLinkedIn, AddCookie
            services.AddAuthentication()
                .AddLinkedIn(o =>
                
                    IConfigurationSection linkedinAuthNSection = 
                        Configuration.GetSection("Authentication:Linkedin");

                    o.ClientId = linkedinAuthNSection["ClientId"];
                    o.ClientSecret = linkedinAuthNSection["ClientSecret"];
                )
                .AddCookie(o =>
                
                    o.LoginPath = "/login";
                    o.LogoutPath = "/logout";
                );
            #endregion

            #region Global CORS Policy Declaration
            services.AddCors(o =>
            
                o.AddDefaultPolicy(builder =>
                    builder.AllowAnyMethod()
                        .AllowAnyHeader()
                        .AllowAnyOrigin()
                );
            );
            #endregion 

            services.AddControllersWithViews();

            // In production, the React files will be served from this directory
            services.AddSpaStaticFiles(configuration =>
            
                configuration.RootPath = "client-app/build";
            );
        

Start.cs - Configure()

        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        
            if (env.IsDevelopment())
            
                app.UseDeveloperExceptionPage();
            
            else
            
                app.UseExceptionHandler("/Error");
            

            #region Map/login
            app.Map("/login", builder =>
            
                builder.Run(async context =>
                
                    var properties = new AuthenticationProperties()  RedirectUri = "/" ;

                    await context.ChallengeAsync("LinkedIn", properties);
                );
            );
            #endregion

            #region Map/logout
            app.Map("/logout", builder =>
            
                builder.Run(async context =>
                
                    await context.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);

                    context.Response.Redirect("/");
                );
            );
            #endregion

            app.UseStaticFiles();
            app.UseSpaStaticFiles();
            app.UseRouting();

            app.UseCors();

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

            app.UseEndpoints(endpoints =>
            
                endpoints.MapControllerRoute(
                    name: "default",
                    pattern: "controller/action=Index/id?");
            );

            app.UseSpa(spa =>
            
                spa.Options.SourcePath = Path.Join(env.ContentRootPath, "client-app");

                if (env.IsDevelopment())
                
                    spa.Options.StartupTimeout = TimeSpan.FromSeconds(240);
                    spa.UseReactDevelopmentServer(npmScript: "start");
                
            );
        

【问题讨论】:

★ 我认为缺少的是如何将属性 [EnableCors] 链接到以下路径的属性:app.Map("/login", builder => MapLogin(builder); ); 究竟是什么 cors 错误? cors 错误在指出错误方面非常直接和准确 @KevinB 在开发工具中,它只在网络选项卡 (1) 中显示 CORS。 React 应用程序,在 IIS 中定义为端口 80 的“网站”。 (2) .NET Core REST API 定义为上述“网站”中的“应用程序”,位于不同的物理位置。 (3) React 向 REST API 发出“登录”请求。 (4) “/login”请求向LinkedIn发出一个Authentication Challenge。 (5) 然后我收到一个 CORS 错误 你用什么浏览器提供的信息这么少? 您应该将错误文本放在您的问题中。你被否决了,因为它不存在。谷歌根据其中的文本链接到问题,并且您链接以生成错误是完全短暂的,因为如果它得到修复,它将消失。还有其他一些小事,但这是大事。您的标题也没有帮助,也应该进行编辑以反映错误消息。如何提问->***.com/help/how-to-ask 【参考方案1】:

终于搞定了!

在尝试理解、理解内化之后,我做出了 2 个重大改变。感谢 Chrome Dev Tools 的黄色警告符号⚠,让我可以this article 并更改解决方案的 1。

更改 1

将上述示例代码的主要 sn-ps 应用到我的 React SPA .NET Core 项目中

删除了允许管道路径分支的地图中间件 (app.Map("/login")。

支持 .NET 控制器/操作。

但更具体地说,只是 Action,因为 "/login" 被添加到 URL 的路径中,这使得很难接受成功的登录。

更改 2

仅针对身份验证 UI 交互丢弃 Axios 调用,因为 LinkedIn 不支持它。 LinkedIn OAuth redirect login returning "No 'Access-Control-Allow-Origin' header is present on the requested resource" error

赞成使用 HTML href。

Authentication.cs

    //[Route("[controller]/[action]")]
    [Route("[action]")]
    public class AuthenticationController : Controller
    
        [HttpGet]
        public IActionResult Register(string authType = "LinkedIn")
        
            return Challenge(new AuthenticationProperties()  RedirectUri = "/" );
        

        [HttpGet]
        public IActionResult Login(string authType = "LinkedIn")
        
            return Challenge(new AuthenticationProperties()  RedirectUri = "/" );
        

        [HttpGet]
        public IActionResult Logout()
        
            return SignOut();
        

Start.cs ConfigureServices()

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        
            services.AddRazorPages();

            services.AddAuthentication(o =>
            
                o.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
                o.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
                o.DefaultChallengeScheme = "LinkedIn";
            )
               .AddCookie()
               .AddOAuth("LinkedIn", o =>
               
                   o.CorrelationCookie.HttpOnly = true;
                   o.CorrelationCookie.SameSite = SameSiteMode.Lax;
                   
                   var linkedInSection = Configuration.GetSection("Authentication:LinkedIn");

                   o.ClientId = linkedInSection.GetSection("ClientId").Get<string>();
                   o.ClientSecret = linkedInSection.GetSection("ClientSecret").Get<string>();
                   o.CallbackPath = new PathString(linkedInSection.GetSection("CallbackPath").Get<string>());

                   o.AuthorizationEndpoint = linkedInSection.GetSection("AuthorizationEndpoint").Get<string>();
                   o.TokenEndpoint = linkedInSection.GetSection("TokenEndpoint").Get<string>();
                   o.UserInformationEndpoint = linkedInSection.GetSection("UserInformationEndpoint").Get<string>();

                   o.Scope.Add("r_liteprofile");
                   o.Scope.Add("r_liteprofile");

                   o.Events = new OAuthEvents
                   
                       OnCreatingTicket = async context =>
                       
                           var request = new HttpRequestMessage(HttpMethod.Get, context.Options.UserInformationEndpoint);
                           request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
                           request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", context.AccessToken);

                           var response = await context.Backchannel.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, context.HttpContext.RequestAborted);
                           response.EnsureSuccessStatusCode();

                           var json = JsonDocument.Parse(await response.Content.ReadAsStringAsync());

                           context.RunClaimActions(json.RootElement);
                       
                   ;
               );
        

Start.cs Configure()

        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        
            if (env.IsDevelopment())
            
                app.UseDeveloperExceptionPage();
            
            else
            
                app.UseExceptionHandler("/Error");
            

            app.UseStaticFiles();

            app.UseRouting();

            app.UseAuthentication();

            app.UseEndpoints(endpoints =>
            
                endpoints.MapControllers();
                endpoints.MapRazorPages();
                endpoints.MapControllerRoute(
                    name: "default",
                    pattern: "controller/action=Index/id?");
            );
        

【讨论】:

【参考方案2】:

在您的 Chrome 浏览器中,尝试从 Chrome 网上商店安装一个名为 Access control Allow Origin 的扩展程序。并打开该扩展程序的选项或设置页面,并在文本框中输入您的本地主机地址,如下所示:https://localhost:80 在你的情况下

我曾经遇到过这个问题,这个扩展对我有用..

【讨论】:

安装浏览器扩展是解决 cors 错误的一种非常糟糕的方法。 @igmani 不确定我们是否要走那条路,因为我们不能强迫我们的客户遵循该流程

以上是关于CORS 错误:LinkedIn 身份验证; .NET Core 5 REST API的主要内容,如果未能解决你的问题,请参考以下文章

在 .NET Core 3.1 中添加窗口身份验证后出现 Cors 错误

发送身份验证承载令牌时出现 Cors 策略错误 - node.js(谷歌云功能)

从 localhost 到 rest api 的身份验证结果 CORS 错误

使用护照进行 Facebook 身份验证的 Node+react 应用程序中的 CORS 错误

对 Kong api 网关端点的基本身份验证请求出现 CORS 错误并且未找到预检

使用linkedin进行用户身份验证