asp.net - OpenIddict - 在同一项目中托管身份验证服务器和 Web api 资源

标签 asp.net oauth-2.0 .net-core openiddict

我想使用 OpenIddict 实现 OpenIdConnect/Oauth2 服务器,以保护 .NET core API 应用程序的安全。我见过的大多数示例都将它们作为单独的项目实现。

客户端应用程序是 SPA,我们使用隐式流。

我的解决方案基于此处 OpenIddict 示例中显示的代码: https://github.com/openiddict/openiddict-samples

对于我正在从事的项目,理想情况下,身份验证服务器和 API 使用相同的端口并位于同一个项目中。 (客户的要求之一是他们不希望配置另一台服务器,因为他们拥有 API 资源并且它将位于同一服务器上)

我已经配置了 OpenIddict 并将其与我们的 API 项目结合起来。几乎一切都正常工作 - API 端点受到 [Authorize] 属性的保护,并防止访问 protected API 端点。但是,当API资源受到保护时,返回的结果不是401 Unauthorized HTTP状态码,而是Auth服务器本身的HTML登录页面。

这是我的 Startup.cs 文件中的相关设置代码:

 // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
    {
        loggerFactory.AddConsole(Configuration.GetSection("Logging"));
        loggerFactory.AddDebug();

        app.UseApplicationInsightsRequestTelemetry();

        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
            app.UseDatabaseErrorPage();
            app.UseBrowserLink();
        }
        else
        {
            app.UseExceptionHandler("/Home/Error");
        }

        app.UseApplicationInsightsExceptionTelemetry();

        app.UseStaticFiles();

        app.UseIdentity();

        app.UseCors("AllowAll");
        //app.UseCors(builder =>
        //{
        //    builder.AllowAnyOrigin();//)WithOrigins("http://localhost:9000");
        //    builder.WithMethods("GET","POST", "PUT", "DELETE", "OPTIONS");
        //    builder.WithHeaders("Authorization");
        //});

        app.UseWhen(context => !context.Request.Path.StartsWithSegments("/api"), branch =>
        {
            branch.UseIdentity();
        });

        app.UseWhen(context => context.Request.Path.StartsWithSegments("/api"), branch =>
        {
            branch.UseOAuthValidation();

        });

        app.UseOpenIddict();


        #region Adding resource config here (api)
        // Add external authentication middleware below. To configure them please see http://go.microsoft.com/fwlink/?LinkID=532715

        app.UseOAuthIntrospection(options =>
        {
            options.AutomaticAuthenticate = true;
            options.AutomaticChallenge = true;
            options.Authority = "http://localhost:5000";
            options.Audiences.Add("resource-server-1");
            options.ClientId = "resource-server-1";
            options.ClientSecret = "846B62D0-DEF9-4215-A99D-86E6B8DAB342";
        });

        //app.UseCors(builder => {
        //    builder.WithOrigins("http://localhost:9000");
        //    builder.WithMethods("GET");
        //    builder.WithHeaders("Authorization");
        //});
        #endregion


        app.UseMvcWithDefaultRoute();

        // Seed the database with the sample applications.
        // Note: in a real world application, this step should be part of a setup script.
        InitializeAsync(app.ApplicationServices, CancellationToken.None).GetAwaiter().GetResult();

    }

private async Task InitializeAsync(IServiceProvider services, CancellationToken cancellationToken)
    {
        // Create a new service scope to ensure the database context is correctly disposed when this methods returns.
        using (var scope = services.GetRequiredService<IServiceScopeFactory>().CreateScope())
        {
            var context = scope.ServiceProvider.GetRequiredService<ApplicationDbContext>();
            //await context.Database.EnsureCreatedAsync();

            var manager = scope.ServiceProvider.GetRequiredService<OpenIddictApplicationManager<OpenIddictApplication>>();

            if (await manager.FindByClientIdAsync("MySPA", cancellationToken) == null)
            {
                var application = new OpenIddictApplication
                {
                    ClientId = "MySPA",
                    DisplayName = "MySPA",
                    LogoutRedirectUri = "http://localhost:9000/signout-oidc",
                    RedirectUri = "http://localhost:9000/signin-oidc"
                };

                await manager.CreateAsync(application, cancellationToken);
            }

            if (await manager.FindByClientIdAsync("resource-server-1", cancellationToken) == null)
            {
                var application = new OpenIddictApplication
                {
                    ClientId = "resource-server-1"
                };

                await manager.CreateAsync(application, "846B62D0-DEF9-4215-A99D-86E6B8DAB342", cancellationToken);
            }

        }
    }

不确定如何在同一个项目中同时实现这些。如前所述,除了 API 返回 HTML 登录页面而不是所需的 HTTP 状态之外,一切都“有效”

最佳答案

app.UseIdentity(); 在管道中出现两次,这违背了在 app.UseWhen 中使用 branch.UseIdentity() 的全部目的() 分支构建器(即确保不会为您的 API 端点调用由 Identity 注册的 cookies 中间件)。

删除第一个出现的地方,它应该可以工作。

关于asp.net - OpenIddict - 在同一项目中托管身份验证服务器和 Web api 资源,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42191571/

相关文章:

tfs - 如何将 XUnit 事实关联到 TFS 中的测试用例

asp.net - 获取 asp.net 上的根域

asp.net - 尽管有更多元素要显示,但未显示滚动条

unity3d - 不允许重定向 url localhost 和 127.0.0.1 时如何在 Unity 中从 Sign in with Apple 获取代码

c# - .NET Core 6,选项模式,如何从 appsettings 获取 json 对象数组

c# - 同步延续到底什么时候是危险的?

c# - 使用 LinkBut​​ton 时禁用验证控件

asp.net - WCF WebInvoke属性可以采用GET作为方法吗

java - 如何在成功验证后使用 Microsoft OAuth 获取用户信息

php - 使用 OAuth2 客户端凭证流保护用 PHP 编写的 REST API