c# - ASP.NET Core 2.0 为同一端点结合了 Cookie 和承载授权

标签 c# asp.net .net authentication asp.net-core-2.0

我在 VS17 中使用“Web 应用程序(模型- View - Controller )”模板和“.Net Framework”+“ASP.NET Core 2”作为配置创建了一个新的 ASP.NET Core Web 应用程序项目。身份验证配置设置为“个人用户帐户”。

我有以下示例端点:

[Produces("application/json")]
[Route("api/price")]
[Authorize(Roles = "PriceViwer", AuthenticationSchemes = "Cookies,Bearer")]
public class PriceController : Controller
{

    public IActionResult Get()
    {
        return Ok(new Dictionary<string, string> { {"Galleon/Pound",
                                                   "999.999" } );
    }
}
"Cookies,Bearer"通过连接 CookieAuthenticationDefaults.AuthenticationScheme 得出和 JwtBearerDefaults.AuthenticationScheme .

目标是能够为端点配置授权,以便可以使用 token 和 cookie 身份验证方法访问它。

这是我在 Startup.cs 中进行身份验证的设置:
    services.AddAuthentication()
        .AddCookie(cfg => { cfg.SlidingExpiration = true;})
        .AddJwtBearer(cfg => {
            cfg.RequireHttpsMetadata = false;
            cfg.SaveToken = true;
            cfg.TokenValidationParameters = new TokenValidationParameters() {
                                                    ValidIssuer = Configuration["Tokens:Issuer"],
                                                    ValidAudience = Configuration["Tokens:Issuer"],
                                                    IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["Tokens:Key"]))
                                                };
        });

因此,当我尝试使用浏览器访问端点时,我会收到带有空白 html 页面的 401 响应。
I get the 401 response with a blank html page.

然后我登录,当我再次尝试访问端点时,我得到了相同的响应。

然后,我尝试通过指定承载 token 来访问端点。这将返回带有 200 响应的所需结果。
And that returns the desired result with the 200 response.

那么,如果我删除 [Authorize(AuthenticationSchemes = "Cookies,Bearer")] , 情况正好相反 - cookie 身份验证有效并返回 200,但是与上面使用的相同的不记名 token 方法没有给出任何结果,只是重定向到默认的 AspIdentity 登录页面。

我可以在这里看到两个可能的问题:

1) ASP.NET Core 不允许“组合”身份验证。
2) 'Cookies' 不是有效的模式名称。但是,什么是正确的使用呢?

请指教。谢谢你。

最佳答案

经过数小时的研究和摸索,这就是在 ASP.NET Core 2.2 -> ASP.NET 5.0 中对我有用的方法:

  • 使用 .AddCookie() 和 .AddJwtBearer() 配置方案
  • 使用自定义策略方案转发到正确的身份验证方案。

  • 您不需要在每个 Controller 操作上指定方案,并且两者都适用。 【授权】就够了。
    services.AddAuthentication( config =>
    {
        config.DefaultScheme = "smart";
    } )
    .AddPolicyScheme( "smart", "Bearer or Jwt", options =>
    {
        options.ForwardDefaultSelector = context =>
        {
            var bearerAuth = context.Request.Headers["Authorization"].FirstOrDefault()?.StartsWith( "Bearer " ) ?? false;
            // You could also check for the actual path here if that's your requirement:
            // eg: if (context.HttpContext.Request.Path.StartsWithSegments("/api", StringComparison.InvariantCulture))
            if ( bearerAuth )
                return JwtBearerDefaults.AuthenticationScheme;
            else
                return CookieAuthenticationDefaults.AuthenticationScheme;
        };
    } )
    .AddCookie( CookieAuthenticationDefaults.AuthenticationScheme, options =>
    {
        options.LoginPath = new PathString( "/Account/Login" );
        options.AccessDeniedPath = new PathString( "/Account/Login" );
        options.LogoutPath = new PathString( "/Account/Logout" );
        options.Cookie.Name = "CustomerPortal.Identity";
        options.SlidingExpiration = true;
        options.ExpireTimeSpan = TimeSpan.FromDays( 1 ); //Account.Login overrides this default value
    } )
    .AddJwtBearer( JwtBearerDefaults.AuthenticationScheme, options =>
    {
        options.RequireHttpsMetadata = false;
        options.SaveToken = true;
        options.TokenValidationParameters = new TokenValidationParameters
        {
            ValidateIssuerSigningKey = true,
            IssuerSigningKey = new SymmetricSecurityKey( key ),
            ValidateIssuer = false,
            ValidateAudience = false
        };
    } );
    
    services.AddAuthorization( options =>
    {
        options.DefaultPolicy = new AuthorizationPolicyBuilder( CookieAuthenticationDefaults.AuthenticationScheme, JwtBearerDefaults.AuthenticationScheme )
            .RequireAuthenticatedUser()
            .Build();
    } );
    

    关于c# - ASP.NET Core 2.0 为同一端点结合了 Cookie 和承载授权,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46938248/

    相关文章:

    c# - 如何按每个对象的成员对对象列表进行排序?

    c# - 在页面加载时停止 JavaScript

    c# - 接受 0 或 ASP.NET Web 窗体中范围内的数字

    c# - Matrix3D 有转置方法吗?

    c# - 如何读取 FOR XML SQL Server 查询的完整结果?

    c# - ASP.NET Core 2.1 区域路由不起作用

    c# - WinForms 中的 Button 有一个 CLICK 事件。但是谁告诉 Button 对象它已被单击?

    c# - 应用程序之间的剪贴板传输

    c# - 在调试/单步执行中检查变量时函数评估超时

    c# - Unity3D : Efficiency of using a queue(list) of IEnumerators, C#?