C# 使用Swagger在ASP.NET内核中实现OAuth

C# 使用Swagger在ASP.NET内核中实现OAuth,c#,.net-core,oauth-2.0,swagger,swashbuckle.aspnetcore,C#,.net Core,Oauth 2.0,Swagger,Swashbuckle.aspnetcore,我想在我的web应用程序中实现OAuth,为此,我在我的startup.cs public static IServiceCollection AddSwaggerDocumentation(this IServiceCollection services) { services.AddSwaggerGen(c => { c.SwaggerDoc("v1", new Open

我想在我的web应用程序中实现OAuth,为此,我在我的
startup.cs

public static IServiceCollection AddSwaggerDocumentation(this IServiceCollection services)
        {
            services.AddSwaggerGen(c =>
            {
                c.SwaggerDoc("v1", new OpenApiInfo { Title = "CombiTime API v1.0", Version = "v1" });

                c.AddSecurityDefinition("OAuth2", new OpenApiSecurityScheme
                {
                    Type = SecuritySchemeType.OAuth2,
                    Flows = new OpenApiOAuthFlows
                    {
                        AuthorizationCode = new OpenApiOAuthFlow
                        {
                            AuthorizationUrl = new Uri("http://localhost:4200/login"),
                            TokenUrl = new Uri("http://localhost:4200/connect/token")
                        }
                    }
                });
                c.OperationFilter<AuthorizeOperationFilter>();

                c.AddSecurityRequirement(new OpenApiSecurityRequirement{
                    {
                        new OpenApiSecurityScheme{
                            Reference = new OpenApiReference{
                                Id = "Bearer", //The name of the previously defined security scheme.
                                Type = ReferenceType.SecurityScheme
                            }
                        },new List<string>()
                    }
                });
            });

            return services;
        }

        public static IApplicationBuilder UseSwaggerDocumentation(this IApplicationBuilder app)
        {
            app.UseSwagger();
            app.UseSwaggerUI(c =>
            {
                c.SwaggerEndpoint("/swagger/v1/swagger.json", "Versioned API v1.0");
                c.DocumentTitle = "Title Documentation";
                c.DocExpansion(DocExpansion.None);
                c.RoutePrefix = string.Empty;
                c.OAuthClientId("combitimeapi_swagger");
                c.OAuthAppName("Combitime API");
                c.OAuthUsePkce();
            });

            return app;
        }
services.AddAuthentication(x =>
            {
                x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
            })
            .AddJwtBearer(x =>
            {
                x.RequireHttpsMetadata = false;
                x.SaveToken = true;
                x.TokenValidationParameters = new TokenValidationParameters
                {
                    ValidateIssuerSigningKey = true,
                    IssuerSigningKey = new SymmetricSecurityKey(key),
                    ValidateIssuer = false,
                    ValidateAudience = false
                };
            });

通过使用这段代码,我在我的招摇过市用户界面上得到了一个“授权”按钮,当我点击该按钮时,我将重定向到我的登录页面(前端基于角度)。因此,我将我的
授权URL
作为
http://localhost:4200/login
当我被重定向到登录页面时,我使用有效的凭证登录,我使用jwt令牌登录,为此我在我的
startup.cs中添加了以下代码

public static IServiceCollection AddSwaggerDocumentation(this IServiceCollection services)
        {
            services.AddSwaggerGen(c =>
            {
                c.SwaggerDoc("v1", new OpenApiInfo { Title = "CombiTime API v1.0", Version = "v1" });

                c.AddSecurityDefinition("OAuth2", new OpenApiSecurityScheme
                {
                    Type = SecuritySchemeType.OAuth2,
                    Flows = new OpenApiOAuthFlows
                    {
                        AuthorizationCode = new OpenApiOAuthFlow
                        {
                            AuthorizationUrl = new Uri("http://localhost:4200/login"),
                            TokenUrl = new Uri("http://localhost:4200/connect/token")
                        }
                    }
                });
                c.OperationFilter<AuthorizeOperationFilter>();

                c.AddSecurityRequirement(new OpenApiSecurityRequirement{
                    {
                        new OpenApiSecurityScheme{
                            Reference = new OpenApiReference{
                                Id = "Bearer", //The name of the previously defined security scheme.
                                Type = ReferenceType.SecurityScheme
                            }
                        },new List<string>()
                    }
                });
            });

            return services;
        }

        public static IApplicationBuilder UseSwaggerDocumentation(this IApplicationBuilder app)
        {
            app.UseSwagger();
            app.UseSwaggerUI(c =>
            {
                c.SwaggerEndpoint("/swagger/v1/swagger.json", "Versioned API v1.0");
                c.DocumentTitle = "Title Documentation";
                c.DocExpansion(DocExpansion.None);
                c.RoutePrefix = string.Empty;
                c.OAuthClientId("combitimeapi_swagger");
                c.OAuthAppName("Combitime API");
                c.OAuthUsePkce();
            });

            return app;
        }
services.AddAuthentication(x =>
            {
                x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
            })
            .AddJwtBearer(x =>
            {
                x.RequireHttpsMetadata = false;
                x.SaveToken = true;
                x.TokenValidationParameters = new TokenValidationParameters
                {
                    ValidateIssuerSigningKey = true,
                    IssuerSigningKey = new SymmetricSecurityKey(key),
                    ValidateIssuer = false,
                    ValidateAudience = false
                };
            });

我想在使用有效凭据登录后重定向回swagger UI,但问题是,我在登录后被重定向到仪表板。请帮助我或让我知道我做错了什么

从swagger重定向到登录页面后形成的url为:

http://localhost:4200/login?response_type=code&client_id=combitimeapi_swagger&redirect_uri=http:%2F%2Flocalhost:61574%2Foauth2-redirect.html&state=V2VkIEZlYiAxNyAyMDIxIDIyOjU3OjQ2IEdNVCswNTMwIChJbmRpYSBTdGFuZGFyZCBUaW1lKQ%3D%3D&code_challenge=mT0amBTJgczCZmNSZAYVfjzzpaTiGb68XlyR3RNHuas&code_challenge_method=S256
我的前端在端口4200上运行。 我的大摇大摆在61574端口上运行。 但在输入有效凭证后,我不会被重定向到swagger UI
请帮助我。

如果您查看OAuth网站,案例将根据请求进行描述

按请求定制 通常情况下,开发人员会认为他们需要能够使用 在每个授权请求上使用不同的重定向URL,并将尝试 更改每个请求的查询字符串参数。这不是问题所在 重定向URL的预期用途,并且 授权服务器。服务器应拒绝任何授权 请求的重定向URL与 注册网址

如果客户端希望在重定向URL中包含特定于请求的数据,那么它可以>而不是使用“state”参数来存储>用户重定向后将包含的数据。它可以在状态参数本身中对数据进行编码,也可以使用状态参数作为会话ID在服务器上存储状态

我希望这对你的探索有所帮助


来源:

首先,让我为您的图片添加一些细节:

  • 您有两个应用程序,一个使用API(基于ASP.NET核心),另一个使用前端UI(角度,但这并不重要),重要的是,还有授权/身份验证功能
  • 您可以使用.NETCore 3.1
  • 您为swagger配置授权,这意味着来自swagger UI页面的任何调用都将使用给定的授权参数
  • 因此,对于API应用程序,我们必须添加一个类,该类具有配置我们的招摇过市的帮助器方法:

    public static class ServiceCollectionExtensions
    {
        public static IServiceCollection AddSwaggerDocumentation(this IServiceCollection services)
        {
            services.AddSwaggerGen(c =>
            {
                c.SwaggerDoc("v1", new OpenApiInfo { Title = "CombiTime API v1.0", Version = "v1" });
    
                c.AddSecurityDefinition(
                    "oauth2", 
                    new OpenApiSecurityScheme
                    {
                        Type = SecuritySchemeType.OAuth2,
                        Flows = new OpenApiOAuthFlows
                        {
                            AuthorizationCode = new OpenApiOAuthFlow
                            {
                                AuthorizationUrl = new Uri("https://lvh.me:4201/connect/authorize"),
                                TokenUrl = new Uri("https://lvh.me:4201/connect/token"),
                                Scopes = new Dictionary<string, string> {
                                    { "combitimeapi", "Demo API" }
                                }
                            }
                        }
                    });
                c.OperationFilter<AuthorizeOperationFilter>();
    
                c.AddSecurityRequirement(
                    new OpenApiSecurityRequirement 
                    {
                        {
                            new OpenApiSecurityScheme{
                                Reference = new OpenApiReference{
                                    Id = "oauth2", //The name of the previously defined security scheme.
                                    Type = ReferenceType.SecurityScheme
                                }
                            },
                            new List<string>()
                        }
                    });
            });
    
            return services;
        }
    
        public static IApplicationBuilder UseSwaggerDocumentation(this IApplicationBuilder app)
        {
            app.UseSwagger();
            app.UseSwaggerUI(c =>
            {
                c.SwaggerEndpoint("/swagger/v1/swagger.json", "Versioned API v1.0");
                c.DocumentTitle = "Title Documentation";
                c.DocExpansion(DocExpansion.None);
                c.RoutePrefix = string.Empty;
                c.OAuthClientId("combitimeapi_swagger");
                c.OAuthAppName("Combitime API");
                c.OAuthScopeSeparator(",");
                c.OAuthUsePkce();
            });
    
            return app;
        }
    }
    
    请不要忘记向所有控制器添加属性
    [Authorize]
    ,因为
    authorizationOperationFilter
    假定已完成此操作

    让我们为前端和授权部件查找所需的更改。您应该配置某些特定内容,例如:

  • CORS政策
  • Awailable API客户端(一个是您的Angular UI,另一个是API应用程序)
  • 可获得的API资源
  • 认证和授权方法
  • Startup.cs
    应包含:

    public void ConfigureServices(IServiceCollection services)
    {
        // ... some your code ...
    
        services.AddSwaggerDocumentation();
        services.AddAuthentication("Bearer")
            .AddIdentityServerAuthentication("Bearer", options =>
            {
                options.ApiName = "combitimeapi";
                options.Authority = "https://lvh.me:4201";
            });
    
        // ... some your code ...
    }
    
    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        // ... some your code ...
        app.UseSwaggerDocumentation();
        app.UseRouting();
        app.UseAuthorization();
    
        // ... some your code ...
    
        app.UseEndpoints(endpoints =>
        {
             endpoints.MapControllers();
        });
    }
    
    public void ConfigureServices(IServiceCollection services)
    {
        // ... some your code ...
    
        services.AddCors(policies => {
            policies.AddDefaultPolicy(builder => {
                builder.AllowAnyHeader().AllowAnyMethod().AllowAnyOrigin();
            });
        });
    
        services.AddIdentityServer()
            .AddApiAuthorization<ApplicationUser, ApplicationDbContext>(options => {
                options.Clients.AddIdentityServerSPA("forntend", cfg => {});
                options.Clients.AddNativeApp("combitimeapi_swagger", cfg => {
                    cfg
                        .WithRedirectUri("https://lvh.me:5001/oauth2-redirect.html")
                        .WithScopes("combitimeapi");
                });
                options.ApiResources.AddApiResource("combitimeapi", cfg => {
                    cfg.WithScopes("combitimeapi");
                });
            })
            .AddApiResources();
    
        services
            .AddAuthentication(
                x =>
                {
                    x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                    x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
                })
            .AddIdentityServerJwt();
        // ... some your code ...
    }
    
    public void配置服务(IServiceCollection服务)
    {
    //…一些您的代码。。。
    services.AddCors(策略=>{
    policies.AddDefaultPolicy(生成器=>{
    builder.AllowAnyHeader().AllowAnyMethod().AllowAnyOrigin();
    });
    });
    services.AddIdentityServer()
    .Addapi授权

    输入您的密码,标记范围并按“授权”,在您进行身份验证后,您将获得:

    如果您没有得到成功的结果,请检查前端应用程序的日志,通常它包含错误,可以帮助您找到问题


    希望上面的文字能对您有所帮助。

    启动代码可能有多个问题,请参阅
    AddSwaggerGen

    身份提供程序的配置:

    独立于重定向,您是否能够获得访问令牌,或者是否遇到某种错误,例如在请求中或在身份提供程序本身中

    请注意,您在Swagger中提供的客户端配置必须与Identity Provider中的配置匹配。您似乎在遵循;我们可以观察到,所有his都遵循Identity Server()中的信息

    在对API的调用中设置令牌:

    此外,即使您获得了令牌,我认为您也没有在从Swagger到API本身的后续调用中设置它

    AddSecurityDefinition
    AddSecurityRequirement
    AuthorizeOperationFilter
    通常至少提到一个具有相同标识符的方案,因为第一个方法定义了Swagger进行身份验证的方式,第二个/第三个方法定义了对API的调用进行身份验证的方式(因此,它们必须相互引用)。但是,您在所有三个方法中使用不同的ID—“OAuth2”、“Bearer”和“OAuth2”,因此它们都没有链接

    我不完全了解您的应用程序,但我相信您实际上可能只使用了
    AddSecurityRequirement
    AuthorizeOperationFilter
    中的一个,因为它们都指定了安全性要求。最重要的是引用安全性定义的ID(在您的示例中为“OAuth2”)


    事实上,Scott的例子中使用了was-在他的例子中是“oauth2”,但任何名称/字符串都可以使用。

    有人请帮忙吗?我不知道答案,但我面临着同样的问题。我会在问题符合条件时立即提供悬赏。@Goodnight NerdPred请参阅此链接:(当您从microsoft emai id登录时,此课程是免费的。)“asp.net core和OAuth入门”课程已经定义了所有内容。它帮助了我,现在我可以重定向回。可能您和我一样缺少了一些内容。:@GoodNightnerdPred同样,重定向在HTT上不起作用