在OpenIddict中处理请求时发生未处理的异常 [英] An unhandled exception occurred while processing the request in OpenIddict

查看:79
本文介绍了在OpenIddict中处理请求时发生未处理的异常的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

因此,我正在尝试使用 .NET核心1.1 实现OpenIddict版本 1.0.0-beta2-0580 并且出现以下错误:

So, I'm trying to implement OpenIddict version 1.0.0-beta2-0580 with NET core 1.1 and I get the following error:


处理请求时发生未处理的异常

这是基于以下内容的: https://github.com/openiddict/openiddict-core/tree/dev/samples

This is based on this : https://github.com/openiddict/openiddict-core/tree/dev/samples

< img src = https://i.stack.imgur.com/8uxMT.png alt =连接休息电话>

数据库正确注册了数据库,设置已加载,一切都在这里工作。数据库中的表: __ efmigrationshistory aspnetroleclaims aspnetroles aspnetuserclaims aspnetuserlogins aspnetuserroles aspnetusers aspnetusertokens basetransaction openiddictapplications openiddict授权 openiddictscopes openiddicttokens

The db registers the database correctly, the settings is loaded and everything works here. The tables in the db: __efmigrationshistory, aspnetroleclaims, aspnetroles, aspnetuserclaims, aspnetuserlogins, aspnetuserroles, aspnetusers, aspnetusertokens, basetransaction, openiddictapplications, openiddictauthorizations, openiddictscopes, openiddicttokens

然后有以下堆栈跟踪:

InvalidOperationException: The authentication ticket was rejected because the mandatory subject claim was missing.
AspNet.Security.OpenIdConnect.Server.OpenIdConnectServerHandler+<HandleSignInAsync>d__5.MoveNext()
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
Microsoft.AspNetCore.Authentication.AuthenticationHandler+<SignInAsync>d__66.MoveNext()
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
Microsoft.AspNetCore.Http.Authentication.Internal.DefaultAuthenticationManager+<SignInAsync>d__14.MoveNext()
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
Microsoft.AspNetCore.Mvc.SignInResult+<ExecuteResultAsync>d__14.MoveNext()
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker+<InvokeResultAsync>d__30.MoveNext()
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker+<InvokeNextResultFilterAsync>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+<InvokeNextResourceFilter>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+<InvokeAsync>d__20.MoveNext()
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
Microsoft.AspNetCore.Builder.RouterMiddleware+<Invoke>d__4.MoveNext()
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
Microsoft.VisualStudio.Web.BrowserLink.BrowserLinkMiddleware+<ExecuteWithFilter>d__7.MoveNext()
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware+<Invoke>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<User, IdentityRole>(config => { config.SignIn.RequireConfirmedEmail = requireConfirmEmail; })
          .AddEntityFrameworkStores<DatabaseContext>()
          .AddDefaultTokenProviders();

    services.AddOpenIddict(options =>
    {
        // Register the Entity Framework stores.
        options.AddEntityFrameworkCoreStores<DatabaseContext>();

        // 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();
    });
}

然后在配置中我有这个:

And then at the configure I have this :

// 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<IServiceScopeFactory>().CreateScope())
    {
        var context = scope.ServiceProvider.GetRequiredService<DatabaseContext>();

        await context.Database.MigrateAsync();

        OpenIddictApplicationManager<OpenIddictApplication> manager = scope.ServiceProvider.GetRequiredService<OpenIddictApplicationManager<OpenIddictApplication>>();

        // ---- Delete code comment ----------
        // 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控制器如下所示:

Then the auth controllers look like this:

public class AuthorizationController : Controller
{
    private readonly SignInManager<User> _signInManager;
    private readonly UserManager<User> _userManager;

    public AuthorizationController(
        SignInManager<User> signInManager,
        UserManager<User> userManager)
    {
        _signInManager = signInManager;
        _userManager = userManager;
    }

    [HttpPost("~/connect/token"), Produces("application/json")]
    public async Task<IActionResult> 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<AuthenticationTicket> 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;
    }
}

依赖项:

<PropertyGroup>
    <TargetFramework>netcoreapp1.1</TargetFramework>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="1.1.2" />
    <PackageReference Include="Microsoft.EntityFrameworkCore" Version="1.1.2" />
    <PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="1.1.2" />
    <PackageReference Include="Microsoft.Extensions.Configuration" Version="1.1.2" />
    <PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="1.1.2" />
    <PackageReference Include="Microsoft.Extensions.Configuration.FileExtensions" Version="1.1.2" />
    <PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="1.1.2" />
    <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="1.1.1" />
    <PackageReference Include="Microsoft.AspNetCore.Mvc" Version="1.1.3" />
    <PackageReference Include="Microsoft.AspNetCore.Mvc.Versioning" Version="1.1.0" />
    <PackageReference Include="Microsoft.AspNetCore.StaticFiles" Version="1.1.2" />
    <PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="1.1.2" />
    <PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="1.1.2" />
    <PackageReference Include="Microsoft.VisualStudio.Web.BrowserLink" Version="1.1.2" />
    <PackageReference Include="Newtonsoft.Json" Version="10.0.2" />
    <PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="1.1.0" />
    <PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="1.1.2" />
    <PackageReference Include="OpenIddict" Version="1.0.0-beta2-0615" />
    <PackageReference Include="OpenIddict.EntityFrameworkCore" Version="1.0.0-beta2-0615" />
    <PackageReference Include="OpenIddict.Mvc" Version="1.0.0-beta2-0615" />

  </ItemGroup>

  <ItemGroup>
    <DotNetCliToolReference Include="Microsoft.EntityFrameworkCore.Tools.DotNet" Version="1.0.1" />
  </ItemGroup>


推荐答案

您看到的错误是由以下事实引起的您的 ClaimsPrincipal 没有强制性的 sub 声明,如异常消息所示。

The error you're seeing is caused by the fact your ClaimsPrincipal doesn't have the mandatory sub claim, as indicated by the exception message.

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

To fix that, you have two options: manually adding the sub claim or asking Identity to use sub as the name identifier claim.

sub 声明添加到返回的主体中通过 await _signInManager.CreateUserPrincipalAsync(user); ...

Add the sub claims to the principal returned by 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 作为名称标识符声明:

... or ask Identity to use sub as the name identifier claim:

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

这篇关于在OpenIddict中处理请求时发生未处理的异常的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆