0

我最近将我的项目从 ASP.NET core 1.1 更新到 ASP.NET core 2.0。我正在使用openiddict进行身份验证。

这是我的控制器,负责请求/响应。

[HttpPost("token")]
public async Task<IActionResult> TokenAsync(OpenIdConnectRequest request)
{
    try
    {
        var ticket = await _service.ExchangeTokenAsync(request);

        return SignIn(ticket.Principal, ticket.Properties,ticket.AuthenticationScheme);;

    }
    catch (Exception ex)
    {
        return BadRequest(new OpenIdConnectResponse
        {
            Error = OpenIdConnectConstants.Errors.ServerError,
            ErrorDescription = ex.Message
        });
    }
}

这个退货声明

return SignIn(ticket.Principal, ticket.Properties,ticket.AuthenticationScheme);

抛出 500 内部服务器错误。该代码在此返回语句之前完美运行,但在执行此返回语句时出现 500 内部服务器错误。

这是我的文件方法的启动。

public void ConfigureServices(IServiceCollection services)
{
    var connectionString = Configuration["ConnectionStrings:ApplicationDbContext"];

    services.AddEntityFrameworkNpgsql();

    services.AddDbContext<ApplicationDbContext>(
        opts =>
        {
            opts.UseNpgsql(connectionString, b => b.MigrationsAssembly("MenuSystem.Repository"));
            opts.UseOpenIddict();
        }
    );

    services.AddIdentity<ApplicationUser, IdentityRole>()
        .AddEntityFrameworkStores<ApplicationDbContext>()
        .AddDefaultTokenProviders();

    var validIssuer = Configuration["Token:Issuer"];
    services.AddAuthentication()
        .AddJwtBearer(cfg =>
        {
            cfg.TokenValidationParameters = new TokenValidationParameters
            {
                ValidIssuer = validIssuer,
                IssuerSigningKey = securityKey,

                ValidateIssuer = !String.IsNullOrEmpty(validIssuer),
                ValidateAudience = false,
                ValidateLifetime = true,
                ValidateActor = false,
                ValidateIssuerSigningKey = true
            };
        });

    services.AddOpenIddict(options =>
    {
        // Register the Entity Framework stores.
        options.AddEntityFrameworkCoreStores<ApplicationDbContext>();
        options.AddMvcBinders();
        options.EnableTokenEndpoint("/api/account/token");
        options.UseJsonWebTokens();
        options.AllowPasswordFlow();
        options.AllowCustomFlow("urn:ietf:params:oauth:grant-type:facebook_access_token");
        options.AllowCustomFlow("urn:ietf:params:oauth:grant-type:google_access_token");
        options.AllowCustomFlow("urn:ietf:params:oauth:grant-type:microsoft_access_token");
        options.DisableHttpsRequirement();
        options.AddSigningKey(securityKey);

    });


    services.Configure<IdentityOptions>(options =>
    {
        // Password settings
        options.Password.RequireDigit = true;
        options.Password.RequiredLength = 8;
        options.Password.RequireNonAlphanumeric = false;
        options.Password.RequireUppercase = true;
        options.Password.RequireLowercase = false;

        // Lockout settings
        options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(30);
        options.Lockout.MaxFailedAccessAttempts = 10;

        // User settings
        options.User.RequireUniqueEmail = true;
    });


    services.AddCors(o => o.AddPolicy("CorsPolicy", builder =>
    {
        builder.AllowAnyOrigin()
                .AllowAnyMethod()
                .AllowAnyHeader();
    }));

    // Add framework services.
    services.AddMvc(options =>
    {
        options.Filters.Add(new GlobalExceptionFilter());
    });   

    services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
}

// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public virtual void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory, RoleManager<IdentityRole> roleManager)
{
    loggerFactory.AddConsole(Configuration.GetSection("Logging"));
    loggerFactory.AddDebug();

    app.UseAuthentication();
    app.UseCors("CorsPolicy");

    app.UseMvc();
}

这是调试日志

   info: Microsoft.AspNetCore.Mvc.SignInResult[1]
Project>       Executing SignInResult with authentication scheme (ASOS) and the following principal: System.Security.Claims.ClaimsPrincipal.
Project> info: Microsoft.AspNetCore.Mvc.SignInResult[1]
Project>       Executing SignInResult with authentication scheme (ASOS) and the following principal: System.Security.Claims.ClaimsPrincipal.
Project> info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2]
Project>       Executed action Project.Controllers.AccountController.TokenAsync (Project) in 15632.6224ms
Project> info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2]
Project>       Executed action Project.Controllers.AccountController.TokenAsync (Project) in 15632.6224ms
Project> fail: Microsoft.AspNetCore.Server.Kestrel[13]
Project>       Connection id "0HL852SU6TGOD", Request id "0HL852SU6TGOD:00000004": An unhandled exception was thrown by the application.
Project> System.InvalidOperationException: The authentication ticket was rejected because the mandatory subject claim was missing.
Project>    at AspNet.Security.OpenIdConnect.Server.OpenIdConnectServerHandler.<SignInAsync>d__6.MoveNext()
Project> --- End of stack trace from previous location where exception was thrown ---
4

1 回答 1

0

此答案是从原始答案 https://stackoverflow.com/a/44845552复制而来

您看到的错误是由于您ClaimsPrincipal没有强制sub声明,如异常消息所示

要解决此问题,您有两种选择:手动添加sub声明或要求 Identitysub用作名称标识符声明

将子声明添加到返回的主体中 await _signInManager.CreateUserPrincipalAsync(user);...

// Note: while ASP.NET Core Identity uses the legacy WS-Federation claims (exposed by the ClaimTypes class),
// OpenIddict uses the newer JWT claims defined by the OpenID Connect specification. To ensure the mandatory
// subject claim is correctly populated (and avoid an InvalidOperationException), it's manually added here.
if (string.IsNullOrEmpty(principal.FindFirstValue(OpenIdConnectConstants.Claims.Subject)))
{
    identity.AddClaim(new Claim(OpenIdConnectConstants.Claims.Subject, await _userManager.GetUserIdAsync(user)));
}

...或要求 Identitysub用作名称标识符声明:

   services.Configure<IdentityOptions>(options =>
{
    options.ClaimsIdentity.UserNameClaimType = OpenIdConnectConstants.Claims.Name;
    options.ClaimsIdentity.UserIdClaimType = OpenIdConnectConstants.Claims.Subject;
    options.ClaimsIdentity.RoleClaimType = OpenIdConnectConstants.Claims.Role;
});
于 2017-09-26T20:16:47.570 回答