【问题标题】:Is there a way to add claims in an ASP.NET Core middleware after Authentication?有没有办法在身份验证后在 ASP.NET Core 中间件中添加声明?
【发布时间】:2019-04-16 22:51:06
【问题描述】:

我的创业公司有这个:

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseHsts();
    }

    app.UseHttpsRedirection();
    app.UseStaticFiles();
    app.UseSwaggerWithUi();

    app.UseAuthentication();
    app.UseMiddleware<SomeMiddleware>();

    app.UseMvc();
}

我需要在用户通过身份验证后添加一些额外的声明,但中间件 Invoke 函数总是在 Auth 之前触发(HttpContext.User.Identity.IsAuthenticated 为 false)。但是当它到达控制器时,用户就可以通过身份验证。

知道在这里做什么吗?我尝试在调用app.UseMiddleware 后输入“app.UseAuthentication()”,但没有任何影响。

我目前正在使用多个身份验证方案。我不确定这是否有影响。

【问题讨论】:

  • 您找到解决方案了吗?我在完全相同的概率上运行(两个 JWT 方案,没有默认值),而且我也总是让用户在我的中间件中没有经过身份验证。
  • 对于那些关注相同问题的人,这个答案解释了为什么会发生这种情况:stackoverflow.com/a/46309119/2689390。所以,我在app.UseAuthorization() 之后移动了我的app.UseMiddleware&lt;SomeMiddleware&gt;();

标签: c# asp.net-core


【解决方案1】:

是的,这是可能的,但您必须添加ClaimsIdentity 类型的新身份,而不是添加到现有声明列表中。

public class SomeMiddleware
{
    private readonly RequestDelegate _next;

    public SomeMiddleware(RequestDelegate next)
    {
        _next = next;
    }

    public async Task InvokeAsync(HttpContext httpContext)
    {
        if (httpContext.User != null && httpContext.User.Identity.IsAuthenticated)
        {
            var claims = new List<Claim>
            {
                new Claim("SomeClaim", "SomeValue")
            };

            var appIdentity = new ClaimsIdentity(claims);
            httpContext.User.AddIdentity(appIdentity);                
        }

        await _next(httpContext);
    }
}

【讨论】:

  • 如果 httpContext.User.Identity.IsAuthenticated 始终为假,这将如何工作?
  • 这个中间件必须在 Configure 方法中的 UseAuthentication 中间件之后添加,该方法首先对用户进行身份验证。如果用户没有为此目的进行身份验证,但您仍然需要设置声明(不确定这是否有意义),您可以删除此条件或实施不同的逻辑。
  • "但不是添加到现有声明列表中,而是必须添加一个新的类型标识" 实际上你没有。您可以将声明添加到现有身份。 HttpContext.User.Identities.FirstOrDefault().AddClaim(new Claim("user_id", "hello world"));
【解决方案2】:

您可以在 UseAuthentication() 之后立即添加另一个中间件以添加声明:

app.UseAuthentication();
app.Use(async(context, next)=>{
    if(context.User !=null && context.User.Identity.IsAuthenticated){
        // add claims here 
        context.User.Claims.Append(new Claim("type-x","value-x"));
    }
    await next();
});

//  call other middlewares 
app.UseMiddleware<SomeMiddleware>();

【讨论】:

  • 试过这个,不好。这仅在我有默认身份验证方案时才有效。
  • @Yodacheese 据我所知,每个请求都会调用AuthenticationMiddleware。声明将在身份验证之后和任何其他中间件之前添加。它不关心是否有默认方案。能否请您详细说明This works only if I have a default auth scheme
  • 当我刷新页面时,声明不知何故消失了。知道为什么吗?
  • @Enrico context.User.Claims.Append 返回另一个列表
【解决方案3】:

您可以编写自己的中间件来添加新的声明。

public class YourCustomMiddleware
{
    private readonly RequestDelegate _next;

    public YourCustomMiddleware(RequestDelegate next)
    {
        _next = next;
    }

    public async Task InvokeAsync(HttpContext httpContext)
    {
        if (httpContext.User != null && httpContext.User.Identity.IsAuthenticated)
        {

            httpContext.User.Identities.FirstOrDefault().AddClaim(new Claim("your claim", "your field"));
        }
        await _next(httpContext);
    }
}

在你的应用启动中

app.UseAuthentication();
app.UseMiddleware<YourCustomMiddleware>();

【讨论】:

    【解决方案4】:

    .NET Core 2.x 的首选方法是使用 IClaimsTransformation,它有一个带有注释的 TransformAsync(ClaimsPrincipal) 方法

    提供一个中心变换点来改变指定的 主要的。注意:这将在每个 AuthenticateAsync 调用上运行,所以 如果您的转换是,则返回新的 ClaimsPrincipal 会更安全 不是幂等的。

    根据扩充的性质,我将声明添加到现有的经过身份验证的身份中,或者创建一个新身份并将其标记为经过身份验证。使用第二个想法,您可以通过在尝试扩充之前检查您的自定义身份来使您的方法具有幂等性。

    【讨论】:

    • 您能否添加更多关于如何实际使用它的信息?一个例子是理想的。
    • 有希望但我仍然没有找到一种方法来持久化声明(大概是添加到现有身份,尽管可能还有另一种方法可以通过 cookie/令牌来持久化它)。所以我同意需要更多信息。我很欣赏 Sanket 提供链接,但其中一个已损坏,MS 并没有谈论坚持索赔,只是拦截了对它的调用。将其添加到传递给 TransformAsync 的 ClaimsPrincipal 中不起作用,并且您不能将其添加到传入的 ClaimsPrincipal 的标识中,因为在编译时它只是一个没有声明能力的 IIdentity。
    • 不确定为什么要保留它,执行声明转换的代码已经具有所需的值,如果计算/检索成本很高,则出于操作目的在其上方放置一个缓存层您只需在每次被告知时添加声明即可。
    • 看看 IDistributedCache,它有一个内存版本,或者如果您需要多节点/区域等,您可以拥有一个 Redis 实例。基本上,您将服务的缓存版本放在从数据库中检索的一个,即装饰器,像 Polly 这样的东西可以在这里提供帮助。
    【解决方案5】:

    这取决于您要做什么以及使用哪种方案。

    例如,如果您使用JwtBearer,那么您可以使用JwtBearerOptions.Events 来处理中间件引发的特定事件。您需要在 Startup 类的 ConfigureServices 方法中设置它。

    这将使您能够更精细地控制要将声明添加到的精确案例,例如OnTokenValidated

    【讨论】:

    • 这很好,但有点乏味。我有多个方案所以JWT只是一个,然后我需要在自定义身份验证方案上添加偶数,同时我仍然想使用依赖注入所以我必须解决它。
    猜你喜欢
    • 2020-04-21
    • 2019-09-20
    • 2018-06-18
    • 2018-07-07
    • 1970-01-01
    • 2020-08-08
    • 2021-01-11
    • 2021-03-13
    • 2018-01-30
    相关资源
    最近更新 更多