如何在 .Net Core 中从 HttpContext 访问声明?

5
使用以下代码进行带有自定义声明的登录,功能正常。
    private async Task SignInAsync(ApplicationUser user)
    {
        var claims = await _claimsPrincipalFactory.CreateAsync(user);

        claims.Identities.First().AddClaims(new[]
        {
            new Claim("xxx", "111"),
            new Claim("yyy", "222")
        });

        await HttpContext.SignInAsync(IdentityConstants.ApplicationScheme, claims);
    }

但是在像下面这样的服务中,尝试使用HttpContext进行访问时

var claims = HttpContext.User.Identities.FirstOrDefault().Claims.ToList();

这将返回0个索赔。

请帮忙。


这项服务在什么时候被使用?它是在中间件中吗?请确保在使用该服务之前调用 app.UseAuthentication() - user4864425
@Ruard 在服务中使用。同时将 services.AddAuthentication 移动到 services 上方,但结果相同。 - Ravi
我的意思是在“Configure”中的顺序,例如app.UseMyMiddlewareThatCallsService(); app.UseAuthentication();。这应该反过来。 - user4864425
如果运行应用程序,则可以访问索赔,方法如下:1.登录->访问索赔。但是,如果执行以下操作,则无法访问索赔:1.注销->登录->现在索赔计数为0。 - Ravi
如果在HttpContext.SignInAsync方法之前设置HttpContext.User = claims,则可以正常工作。即使我尝试使用SignInManager.SignInWithClaimsAsync方法也不起作用。 - Ravi
显示剩余2条评论
4个回答

2
我的假设是由于构建管道的语句顺序不正确导致声明丢失。
在“配置”中,您可以向管道中插入中间件。插入中间件时,顺序很重要,与在“配置服务”中不同。
因此,当在使用声明的中间件中使用服务时,在用户进行身份验证之前使用声明,那么声明尚不可用,例如:
app.UseMyMiddlewareThatCallsService(); 
app.UseAuthentication();

但是当顺序改变时,索赔也会发生变化。
app.UseAuthentication();
app.UseMyMiddlewareThatCallsService(); 

1
取决于模式的实现方式,身份验证处理程序可能默认不会更新 HttpContext.User
例如,cookie 身份验证处理程序不会登录当前用户,而是仅生成身份验证票据并将其设置为响应

SignInAsync 创建加密 cookie 并将其添加到当前响应中。如果未指定 AuthenticationScheme,则使用默认方案。

如果您正在使用 cookie 身份验证,可以处理 CookieAuthenticationEvents.OnSignedIn 事件以更新 HttpContext.User
.AddCookie(IdentityConstants.ApplicationScheme,
    opt =>
    {
        opt.Events = new CookieAuthenticationEvents
        {
            OnSignedIn = async ctx =>
            {
                ctx.HttpContext.User = ctx.Principal;
            }
        };
    });

我也尝试了你的方法,但事件没有被调用。 - Ravi
@Ravi,答案中提到的事件是使用Cookie身份验证的示例。您正在使用哪种身份验证模式? - weichch
@Ravi 为了测试目的,您是否想要从我的答案中添加 services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme).AddCookie(...) 并尝试 await HttpContext.SignInAsync(IdentityConstants.ApplicationScheme, claims); - weichch
@Ravi 不,AddCookie 必须有一个名称,该名称与您传递到 SignInAsync 中的名称匹配。就像我的答案所做的那样。 - weichch
你的回答提供了修复的线索。谢谢。 - Ravi
显示剩余3条评论

0
if (access token in header or query parameter)
{
    // Set the claims like in the Account/Login action from the interactive login form
    var claims = ...;
    // Local helper method, is used in other places, too
    var claimsIdentity = await SignInAsync(httpContext, claims, false);
    // Set user for the current request
    // This works in that it's in User.Identity, but the auth events won't fire
    httpContext.User = new ClaimsPrincipal(claimsIdentity);
}

0

最终这里是可工作的代码。

        services.ConfigureApplicationCookie(options =>
        {
            options.Events.OnSignedIn = (context) =>
            {
                context.HttpContext.User = context.Principal;
                return Task.CompletedTask;
            };
        });

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接