C# 调用控制器时,何时分配用户的身份?

C# 调用控制器时,何时分配用户的身份?,c#,asp.net-core,jwt,claims-based-identity,C#,Asp.net Core,Jwt,Claims Based Identity,我正在调用控制器中的一个方法,并在其构造函数中命中一个断点。检查User.Claims.First(…)会抛出一个异常,经过仔细调查后,发现该用户为null 这是有道理的,因为控制器不知道调用它的匿名用户是谁。然后,我添加了头授权,通过持有者xxx.yyy.zzz(邮递员和我的应用程序)对其进行估价。令牌是正确的,因为篡改它会导致状态代码401未经授权 因此,我的结论是,安全设置起作用了,策略的行为与预期的一样(使用与缺少所述操作的权限的用户对应的令牌进行调用,但不会执行所述操作) 将令牌文本粘

我正在调用控制器中的一个方法,并在其构造函数中命中一个断点。检查User.Claims.First(…)会抛出一个异常,经过仔细调查后,发现该用户为null

这是有道理的,因为控制器不知道调用它的匿名用户是谁。然后,我添加了头授权,通过持有者xxx.yyy.zzz(邮递员和我的应用程序)对其进行估价。令牌是正确的,因为篡改它会导致状态代码401未经授权

因此,我的结论是,安全设置起作用了,策略的行为与预期的一样(使用与缺少所述操作的权限的用户对应的令牌进行调用,但不会执行所述操作)

将令牌文本粘贴到jwt.io可以提供有关声明的预期详细信息。因此,我的结论是令牌应该是可读的,并且可以被应用程序的库解析

所以问题是这个用户如何为控制器实例化(何时、何地、基于什么?或者,如何搜索它(我已经尝试了一段时间,但我意识到我正在黑暗中摸索一棵随机树)

令牌以以下方式配备索赔

Claim[] claims =
{
  new Claim(ClaimTypes.Expiration, TokenExpiration.ToString(), ClaimValueTypes.DateTime),
  new Claim(ClaimTypes.Name, userName, ClaimValueTypes.String),
  new Claim(ClaimTypes.Role, member.Privilege + "", ClaimValueTypes.Integer),
  new Claim(ClaimTypes.Version, "0.1", ClaimValueTypes.String),
  new Claim(ClaimTypes.Webpage, "xxx.azurewebsites.net", ClaimValueTypes.String),
  new Claim("NetworkId", member.Network.Id.ToString(), ClaimValueTypes.String),
  new Claim("MemberId", member.Id.ToString(), ClaimValueTypes.String),
  new Claim("Author", "yyy", ClaimValueTypes.String)
};
SymmetricSecurityKey key = new SymmetricSecurityKey(SecurityKey);
SigningCredentials credentials = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);

JwtSecurityToken token = new JwtSecurityToken(
  "xxx.azurewebsites.net",
  "xxx.azurewebsites.net",
  claims,
  DateTime.UtcNow,
  TokenExpiration,
  credentials);
string output = new JwtSecurityTokenHandler().WriteToken(token);
编辑启动设置如下

services.AddSingleton<IUtilityService, UtilityService>();
services.AddSingleton<IEmailService, EmailService>();
services.AddCors(_ => _.AddPolicy("Open policy", __ => __
  .AllowAnyOrigin()
  .AllowAnyHeader()
  .AllowAnyMethod()));
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
  .AddJwtBearer(_ =>
  {
    _.TokenValidationParameters = new TokenValidationParameters
    {
      ValidateIssuerSigningKey = true,
      ValidateAudience = false,
      ValidateIssuer = false,
      ValidateActor = true,
      ValidateLifetime = true,
      IssuerSigningKey = new SymmetricSecurityKey( ... )
    };
  });
  services.AddAuthorization(_ => _.AddPolicy("Common", __ => ... ));
  services.AddAuthorization(_ => _.AddPolicy("Super", __ => ... ));
  services.AddAuthorization(_ => _.AddPolicy("Admin", __ => ... ));
  services.AddMvc()
    .AddJsonOptions(_ => ...);
  services.AddSwaggerGen(_ => ... );
  services.AddDbContext<Context>(_ => _.UseSqlServer( ... ));
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
  if (env.IsDevelopment())
    app.UseDeveloperExceptionPage();

  app.Use(async (context, next) =>
  {
    try { await next(); }
    catch (Exception) { context.Response.StatusCode = ... }
  });

  app.UseCors("Open policy");
  app.UseAuthentication();
  app.UseMvc();
  app.UseSwagger();
  app.UseSwaggerUI(...);
}

我通过分析事件管道(如@amy所述)解决了这个问题,并注意到操作调用之前有OnActionExecuting方法(由@sixtosaez提供)


我可以想象,在Start中更改中间件的注册顺序(如@MarkG所述)也可以开始工作,但由于不存在任何问题和混乱,我对处理这些问题没有信心。

用户原则是在身份验证中间件中设置的。对于cookie中间件,这发生在
CookieAuthenticationHandler.AuthenticateCoreAsync
中。如果您共享启动代码,这将非常有用。中间件的顺序也很重要。@MarkG很抱歉忽略了这一点。很明显,你提到了。然而,直到现在我才意识到这一点。请稍后查看编辑。@Amy我已经用启动更新了问题。我可以看到在哪里进行身份验证和授权。然而,我不清楚哪些步骤对应于控制器构造函数的调用。请告知。(另外,我使用的不是cookies,而是JWTokens,如果这有什么意义的话。)@DonkeyBanana您所问的是Web API管道:更改中间件的注册顺序是什么意思?玩弄这些东西没什么害处……这是学习的最佳方式。@Brad如果你查看对问题的评论,你会看到MarkG说中间件注册的顺序确实会影响执行顺序的行为。因为我在总结别人说的话,所以我也想把这条信息带进来。然而,由于我还没有尝试过,我不能保证它确实解决了我的问题。@Brad我决不是在暗示,如果一个人想要学习,就玩弄注册顺序是有害的。不过,我没有时间,其他提示实际上解决了我的问题。我选择了不篡改中间件,因为我担心会对应用程序中的其他内容造成损害。如果您觉得可以就中间件的基于订单的原始问题解决方案提供建议,那么欢迎并敦促您发布建议。实际上,您还没有显示中间件注册的顺序。中间件通常使用
app.UseXXX(…)在
Startup.Configure(IAApplicationBuilder app)
方法中注册语句和顺序非常重要。您只显示了您的服务注册
services.AddXXX(…)并不总是重要的,这取决于您注册的服务(如果在构建
IServiceProvider
之前未注册其他服务,则某些服务可能引发异常)。@Brad So Dumble。。。当然,你是对的。我被所有的东西弄糊涂了,最后忘了发了。请看一下最新的问题。
public override void OnActionExecuting(ActionExecutingContext context)
{
  Claim claim = User.Claims
    .First(_ => _.Type == "MemberId");
  ...
}