C# 即使手动使用HttpContext.SignInAsync,.Net Core也被验证为false

C# 即使手动使用HttpContext.SignInAsync,.Net Core也被验证为false,c#,authentication,asp.net-core,jwt,C#,Authentication,Asp.net Core,Jwt,我的应用程序同时使用cookie和承载身份验证: var membershipService = configuration.GetValue<string>("MembershipService:BaseUri"); services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) .AddCookie() .AddJwtBearer(opt => { opt.Audi

我的应用程序同时使用cookie和承载身份验证:

var membershipService = configuration.GetValue<string>("MembershipService:BaseUri");
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddCookie()
    .AddJwtBearer(opt =>
    {
        opt.Audience = "gateway";
        opt.Authority = membershipService;
        opt.RequireHttpsMetadata = false;
        opt.SaveToken = true;
        opt.Events = new JwtBearerEvents()
        {
            OnTokenValidated = (context) =>
            {
                var accessToken = context.SecurityToken as JwtSecurityToken;
                if (accessToken != null)
                {
                    ClaimsIdentity identity = context.Principal.Identity as ClaimsIdentity;
                    if (identity != null)
                    {
                        identity.AddClaim(new Claim("access_token", accessToken.RawData));
                    }
                }
                return Task.CompletedTask;
            }
        };
});
var membershipService=configuration.GetValue(“membershipService:BaseUri”);
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddCookie()
.AddJwtBearer(opt=>
{
opt.viewer=“网关”;
opt.Authority=会员服务;
opt.requirehttpsmatadata=false;
opt.SaveToken=true;
opt.Events=newjwtbearerevents()
{
OnTokenValidated=(上下文)=>
{
var accessToken=context.SecurityToken作为JwtSecurityToken;
if(accessToken!=null)
{
ClaimsIdentity identity=context.Principal.identity作为ClaimsIdentity;
if(标识!=空)
{
AddClaim(新声明(“access_token”,accessToken.RawData));
}
}
返回Task.CompletedTask;
}
};
});
当我在标题中发送
access\u令牌时,一切正常

但是,如果我在第二个请求(第一个请求带有授权头)的头中发送不带令牌的消息,则似乎
用户
对以前的身份验证一无所知。即使我执行了http://code>HttpContext.SignInAsync(“Cookies”,User)
,下一个请求(例如,在按F5之后)也不会对用户进行身份验证


我错过了什么

首先,除非您实际调用cookie方案上的
SignInAsync
,否则不会创建cookie。所以你需要这样做。但仅仅因为用户正在发送cookie,并不意味着cookie方案将运行并尝试对用户进行身份验证

您可以这样调用
AddAuthentication

services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
这意味着JWT承载身份验证将是默认的身份验证方案。因此,当身份验证中间件运行时,它将尝试对该身份验证方案进行身份验证,并且仅对该方案进行身份验证。如果您有多个身份验证方案,则只有默认身份验证方案将实际尝试对用户进行身份验证。否则,如果多个方案可以对用户进行身份验证,则会发生冲突

因此,在您的情况下,用户没有得到身份验证,因为cookie身份验证方案根本没有运行。你应该考虑一下你的默认方案应该是什么。如果您只想将承载令牌用作“登录”,那么使用cookie身份验证方案作为默认方案是有意义的。然后,您可以提供需要承载方案的登录操作,然后在cookie方案中签名:

[Authorize(AuthenticationSchemes=JwtBearerDefaults.AuthenticationScheme)]
public async Task<IActionResult> Login()
{
    await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, User);
    return View();
}
[授权(AuthenticationSchemes=JwtBearerDefaults.AuthenticationScheme)]
公共异步任务登录()
{
等待HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme,用户);
返回视图();
}
然后,您可以使用
access\u令牌调用该路由,并让
Authorize
属性触发JWT承载方案上的身份验证,并使用用户使用cookie方案登录。因此,后续的请求将使用cookie方案(默认情况),并且用户将被识别


最后请注意,JWT承载身份验证通常被视为无状态身份验证方法,在每个请求上显式发送令牌被认为是正确的做法。因此,从中生成cookie有点奇怪。

首先,除非在cookie方案上实际调用
SignInAsync
,否则不会创建cookie。所以你需要这样做。但仅仅因为用户正在发送cookie,并不意味着cookie方案将运行并尝试对用户进行身份验证

您可以这样调用
AddAuthentication

services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
这意味着JWT承载身份验证将是默认的身份验证方案。因此,当身份验证中间件运行时,它将尝试对该身份验证方案进行身份验证,并且仅对该方案进行身份验证。如果您有多个身份验证方案,则只有默认身份验证方案将实际尝试对用户进行身份验证。否则,如果多个方案可以对用户进行身份验证,则会发生冲突

因此,在您的情况下,用户没有得到身份验证,因为cookie身份验证方案根本没有运行。你应该考虑一下你的默认方案应该是什么。如果您只想将承载令牌用作“登录”,那么使用cookie身份验证方案作为默认方案是有意义的。然后,您可以提供需要承载方案的登录操作,然后在cookie方案中签名:

[Authorize(AuthenticationSchemes=JwtBearerDefaults.AuthenticationScheme)]
public async Task<IActionResult> Login()
{
    await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, User);
    return View();
}
[授权(AuthenticationSchemes=JwtBearerDefaults.AuthenticationScheme)]
公共异步任务登录()
{
等待HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme,用户);
返回视图();
}
然后,您可以使用
access\u令牌调用该路由,并让
Authorize
属性触发JWT承载方案上的身份验证,并使用用户使用cookie方案登录。因此,后续请求将使用cookie方案(作为默认方案),用户将被识别


最后请注意,JWT承载身份验证通常被视为无状态身份验证方法,在每个请求上显式发送令牌被认为是正确的做法。因此,从中生成cookie有点奇怪。

一个绝妙的解决方案!非常清楚的解释,谢谢。事实上,我有SPA,我需要cookies认证方案只用于页面刷新,因为如果用户登录,我会在第一次请求时提取一些初始用户数据。这是一个绝妙的解决方案!非常清楚的解释,谢谢。事实上,我有SPA,我需要cookies认证方案,只用于页面刷新,因为我有一些初始设置