在OpenIddict中处理请求时发生未处理的exception

所以,我正在尝试使用.net核心1.1实现OpenIddict版本1.0.0-beta2-0580,我收到以下错误:

处理请求时发生未处理的exception

这是基于此: https : //github.com/openiddict/openiddict-core/tree/dev/samples 连接休息电话

db正确注册数据库,加载设置,一切都在这里工作。 数据库中的表格: __efmigrationshistoryaspnetroleclaimsaspnetrolesaspnetuserclaimsaspnetuserloginsaspnetuserrolesaspnetusersaspnetusertokensbasetransactionopeniddictapplicationsopeniddictauthorizationsopeniddictscopesopeniddicttokens

然后我有

堆栈跟踪:

 InvalidOperationException: The authentication ticket was rejected because the mandatory subject claim was missing. AspNet.Security.OpenIdConnect.Server.OpenIdConnectServerHandler+d__5.MoveNext() System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) Microsoft.AspNetCore.Authentication.AuthenticationHandler+d__66.MoveNext() System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) Microsoft.AspNetCore.Http.Authentication.Internal.DefaultAuthenticationManager+d__14.MoveNext() System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) Microsoft.AspNetCore.Mvc.SignInResult+d__14.MoveNext() System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker+d__30.MoveNext() System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker+d__28.MoveNext() System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Rethrow(ResultExecutedContext context) Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Next(ref State next, ref Scope scope, ref object state, ref bool isCompleted) Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker+d__22.MoveNext() System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Rethrow(ResourceExecutedContext context) Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Next(ref State next, ref Scope scope, ref object state, ref bool isCompleted) Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker+d__20.MoveNext() System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) Microsoft.AspNetCore.Builder.RouterMiddleware+d__4.MoveNext() System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) Microsoft.VisualStudio.Web.BrowserLink.BrowserLinkMiddleware+d__7.MoveNext() System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware+d__7.MoveNext() 

在创业中我有:

 // This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { // Add framework services. services.AddMvc(); services.RegisterDatabase(aspNet: true, useOpenIddict : true); // Register the Identity services. service.AddIdentity(config => { config.SignIn.RequireConfirmedEmail = requireConfirmEmail; }) .AddEntityFrameworkStores() .AddDefaultTokenProviders(); services.AddOpenIddict(options => { // Register the Entity Framework stores. options.AddEntityFrameworkCoreStores(); // Register the ASP.NET Core MVC binder used by OpenIddict. // Note: if you don't call this method, you won't be able to // bind OpenIdConnectRequest or OpenIdConnectResponse parameters. options.AddMvcBinders(); // Enable the token endpoint. options.EnableTokenEndpoint("/connect/token"); // Enable the password flow. options.AllowPasswordFlow(); // During development, you can disable the HTTPS requirement. options.DisableHttpsRequirement(); // Note: to use JWT access tokens instead of the default // encrypted format, the following lines are required: // // options.UseJsonWebTokens(); // options.AddEphemeralSigningKey(); }); } 

然后在配置我有这个:

 // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IServiceProvider service, IHostingEnvironment env, ILoggerFactory loggerFactory) { app.UseOpenIddict(); // Create a new service scope to ensure the database context is correctly disposed when this methods returns. using (var scope = service.GetRequiredService().CreateScope()) { var context = scope.ServiceProvider.GetRequiredService(); await context.Database.MigrateAsync(); OpenIddictApplicationManager manager = scope.ServiceProvider.GetRequiredService<OpenIddictApplicationManager>(); /*if (await manager.FindByClientIdAsync("mvc", cancellationToken) == null) { var application = new OpenIddictApplication { ClientId = "mvc", DisplayName = "MVC client application", LogoutRedirectUri = "http://localhost:53507/", RedirectUri = "http://localhost:53507/signin-oidc" }; await manager.CreateAsync(application, "901564A5-E7FE-42CB-B10D-61EF6A8F3654", cancellationToken); }*/ // To test this sample with Postman, use the following settings: // // * Authorization URL: http://localhost:54540/connect/authorize // * Access token URL: http://localhost:54540/connect/token // * Client ID: postman // * Client secret: [blank] (not used with public clients) // * Scope: openid email profile roles // * Grant type: authorization code // * Request access token locally: yes var client = await manager.FindByClientIdAsync("postman", cancellationToken); if (client == null) { var application = new OpenIddictApplication { ClientId = "postman", DisplayName = "Postman", }; await manager.CreateAsync(application, cancellationToken); } } if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); app.UseBrowserLink(); } else { app.UseExceptionHandler("/Home/Error"); } app.UseStaticFiles(); app.UseMvc(routes => { routes.MapRoute( name: "default", template: "{controller=Home}/{action=Index}/{id?}"); }); } 

然后auth控制器看起来像这样:

 public class AuthorizationController : Controller { private readonly SignInManager _signInManager; private readonly UserManager _userManager; public AuthorizationController( SignInManager signInManager, UserManager userManager) { _signInManager = signInManager; _userManager = userManager; } [HttpPost("~/connect/token"), Produces("application/json")] public async Task Exchange(OpenIdConnectRequest request) { Debug.Assert(request.IsTokenRequest(), "The OpenIddict binder for ASP.NET Core MVC is not registered. " + "Make sure services.AddOpenIddict().AddMvcBinders() is correctly called."); if (request.IsPasswordGrantType()) { var user = await _userManager.FindByNameAsync(request.Username); if (user == null) { return BadRequest(new OpenIdConnectResponse { Error = OpenIdConnectConstants.Errors.InvalidGrant, ErrorDescription = "The username/password couple is invalid." }); } // Ensure the user is allowed to sign in. if (!await _signInManager.CanSignInAsync(user)) { return BadRequest(new OpenIdConnectResponse { Error = OpenIdConnectConstants.Errors.InvalidGrant, ErrorDescription = "The specified user is not allowed to sign in." }); } // Reject the token request if two-factor authentication has been enabled by the user. if (_userManager.SupportsUserTwoFactor && await _userManager.GetTwoFactorEnabledAsync(user)) { return BadRequest(new OpenIdConnectResponse { Error = OpenIdConnectConstants.Errors.InvalidGrant, ErrorDescription = "The specified user is not allowed to sign in." }); } // Ensure the user is not already locked out. if (_userManager.SupportsUserLockout && await _userManager.IsLockedOutAsync(user)) { return BadRequest(new OpenIdConnectResponse { Error = OpenIdConnectConstants.Errors.InvalidGrant, ErrorDescription = "The username/password couple is invalid." }); } // Ensure the password is valid. if (!await _userManager.CheckPasswordAsync(user, request.Password)) { if (_userManager.SupportsUserLockout) { await _userManager.AccessFailedAsync(user); } return BadRequest(new OpenIdConnectResponse { Error = OpenIdConnectConstants.Errors.InvalidGrant, ErrorDescription = "The username/password couple is invalid." }); } if (_userManager.SupportsUserLockout) { await _userManager.ResetAccessFailedCountAsync(user); } // Create a new authentication ticket. var ticket = await CreateTicketAsync(request, user); return SignIn(ticket.Principal, ticket.Properties, ticket.AuthenticationScheme); } return BadRequest(new OpenIdConnectResponse { Error = OpenIdConnectConstants.Errors.UnsupportedGrantType, ErrorDescription = "The specified grant type is not supported." }); } private async Task CreateTicketAsync(OpenIdConnectRequest request, User user) { // Create a new ClaimsPrincipal containing the claims that // will be used to create an id_token, a token or a code. var principal = await _signInManager.CreateUserPrincipalAsync(user); // Note: by default, claims are NOT automatically included in the access and identity tokens. // To allow OpenIddict to serialize them, you must attach them a destination, that specifies // whether they should be included in access tokens, in identity tokens or in both. foreach (var claim in principal.Claims) { // In this sample, every claim is serialized in both the access and the identity tokens. // In a real world application, you'd probably want to exclude confidential claims // or apply a claims policy based on the scopes requested by the client application. claim.SetDestinations(OpenIdConnectConstants.Destinations.AccessToken, OpenIdConnectConstants.Destinations.IdentityToken); } // Create a new authentication ticket holding the user identity. var ticket = new AuthenticationTicket( principal, new AuthenticationProperties(), OpenIdConnectServerDefaults.AuthenticationScheme); // Set the list of scopes granted to the client application. // Note: the offline_access scope must be granted // to allow OpenIddict to return a refresh token. ticket.SetScopes(new[] { OpenIdConnectConstants.Scopes.OpenId, OpenIdConnectConstants.Scopes.Email, OpenIdConnectConstants.Scopes.Profile, OpenIdConnectConstants.Scopes.OfflineAccess, OpenIddictConstants.Scopes.Roles }.Intersect(request.GetScopes())); return ticket; } } 

依赖关系:

  netcoreapp1.1                           

您看到的错误是由您的ClaimsPrincipal没有强制sub声明引起的,如exception消息所示。

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

sub声明添加到await _signInManager.CreateUserPrincipalAsync(user);返回的主体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))); } 

…或要求Identity使用sub作为名称标识符声明:

 services.Configure(options => { options.ClaimsIdentity.UserNameClaimType = OpenIdConnectConstants.Claims.Name; options.ClaimsIdentity.UserIdClaimType = OpenIdConnectConstants.Claims.Subject; options.ClaimsIdentity.RoleClaimType = OpenIdConnectConstants.Claims.Role; }); 

打开文件startup.cs并在ConfigureServices中使用下面的代码

services.AddTransient();

将模型名称用于<>