使用 OpenIddict 刷新令牌始终将主体返回为 null

问题描述

自从从 OpenIdDict 2.x 迁移到 3.X,我们不能再使用 refreshtoken。 我们的代码基于 dotnet core 3.1

用户/密码的处理工作正常,用户收到他的令牌(访问、id 和刷新)

但是一旦我们想要发送刷新令牌,从用户那里获取主体的过程就会返回一个空值。

var 信息 = 等待 HttpContext.AuthenticateAsync(OpenIddictValidationAspNetCoreDefaults.AuthenticationScheme); var user = await _userManager.GetUserAsync(info.Principal);

错误信息

System.ArgumentNullException:值不能为空。 (范围 '校长')

这是我们用来引导 Openiddict 的代码

startup.cs

services.AddOpenIddict()
    .AddCore(options =>
    {
        options.UseEntityFrameworkCore()
            .UseDbContext<DataContext>();
    })
    .AddServer(options =>
    {
        options.SetTokenEndpointUris("/connect/token")
            .AllowPasswordFlow()
            .AllowRefreshTokenFlow();

        options.SetAccesstokenLifetime(TimeSpan.FromDays(1));
        options.SetRefreshTokenLifetime(TimeSpan.FromDays(1));
        options.AcceptAnonymousClients();
        options.AddDevelopmentEncryptionCertificate();
        options.AddDevelopmentSigningCertificate();
        options.RequireProofKeyForCodeExchange();

        options.UseAspNetCore()
            .EnabletokenEndpointPassthrough();
    })
    .AddValidation(options =>
    {
        options.UseLocalServer();
        options.UseAspNetCore();
    });

授权控制器.cs

[HttpPost("~/connect/token")]
public async Task<IActionResult> Login()
{
    var request = HttpContext.GetopenIddictServerRequest() ??
        throw new InvalidOperationException(
            "The OpenID Connect request cannot be retrieved.");

    if (request.IsPasswordGrantType())
    {
        return await CheckPasswordGrantType(request);
    }

    if (request.IsRefreshTokenGrantType())
    {
        return await CheckRefreshTokenGrantType();
    }

    throw new NotImplementedException("The specified grant type is not implemented.");
}

private async Task<IActionResult> CheckRefreshTokenGrantType()
{
    var info = await HttpContext.AuthenticateAsync(
        OpenIddictValidationAspNetCoreDefaults.AuthenticationScheme);

    var user = await _userManager.GetUserAsync(info.Principal);
    if (user == null)
    {
        var properties = new AuthenticationProperties(new Dictionary<string,string>
        {
            [OpenIddictServerAspNetCoreConstants.Properties.Error] =
                OpenIddictConstants.Errors.InvalidGrant,[OpenIddictServerAspNetCoreConstants.Properties.ErrorDescription] =
                "The refresh token is no longer valid."
        });

        return Forbid(properties,OpenIddictValidationAspNetCoreDefaults.AuthenticationScheme);
    }

    if (user.EmailConfirmed == false)
    {
        var properties = new AuthenticationProperties(new Dictionary<string,[OpenIddictServerAspNetCoreConstants.Properties.ErrorDescription] =
                "Email address not confirmed."
        });

        return Forbid(properties,OpenIddictValidationAspNetCoreDefaults.AuthenticationScheme);
    }

    if (!await _signInManager.CanSignInAsync(user))
    {
        var properties = new AuthenticationProperties(new Dictionary<string,[OpenIddictServerAspNetCoreConstants.Properties.ErrorDescription] =
                "The user is no longer allowed to sign in."
        });

        return Forbid(properties,OpenIddictValidationAspNetCoreDefaults.AuthenticationScheme);
    }

    foreach (var claim in info.Principal.Claims)
    {
        claim.SetDestinations(GetDestinations(claim,info.Principal));
    }

    return SignIn(info.Principal,OpenIddictServerAspNetCoreDefaults.AuthenticationScheme);
}

private async Task<IActionResult> CheckPasswordGrantType(OpenIddictRequest request)
{
    var user = await _userManager.FindByNameAsync(request.Username);
    if (user == null)
    {
        var properties = new AuthenticationProperties(new Dictionary<string,string>
        {
            [OpenIddictServerAspNetCoreConstants.Properties.Error] = 
            OpenIddictConstants.Errors.InvalidGrant,[OpenIddictServerAspNetCoreConstants.Properties.ErrorDescription] =
                "The username/password couple is invalid."
        });

        return Forbid(properties,string>
        {
            [OpenIddictServerAspNetCoreConstants.Properties.Error] = 
            OpenIddictConstants.Errors.AccessDenied,[OpenIddictServerAspNetCoreConstants.Properties.ErrorDescription] = 
            "Email address not confirmed."
        });

        return Forbid(properties,OpenIddictValidationAspNetCoreDefaults.AuthenticationScheme);
    }

    var result = 
        await _signInManager.CheckPasswordSignInAsync(user,request.Password,true);
    if (!result.Succeeded)
    {
        if (result.IsLockedOut)
        {
            var properties =
                new AuthenticationProperties(new Dictionary<string,string>
            {
                [OpenIddictServerAspNetCoreConstants.Properties.Error] =
                    OpenIddictConstants.Errors.InvalidRequest,[OpenIddictServerAspNetCoreConstants.Properties.ErrorDescription] =
                    "Account locked : too many attempts."
            });

            return Forbid(properties,OpenIddictValidationAspNetCoreDefaults.AuthenticationScheme);
        }
        else
        {
            var properties = 
                new AuthenticationProperties(new Dictionary<string,string>
            {
                [OpenIddictServerAspNetCoreConstants.Properties.Error] =
                    OpenIddictConstants.Errors.InvalidGrant,[OpenIddictServerAspNetCoreConstants.Properties.ErrorDescription] =
                    "The username/password couple is invalid."
            });
            return Forbid(properties,OpenIddictValidationAspNetCoreDefaults.AuthenticationScheme);
        }
    }

    var principal = await _signInManager.createuserPrincipalAsync(user);
    principal.SetScopes(new[]
    {
                OpenIddictConstants.Scopes.OpenId,OpenIddictConstants.Scopes.Email,OpenIddictConstants.Scopes.Profile,OpenIddictConstants.Scopes.Roles,OpenIddictConstants.Scopes.OfflineAccess
            }.Intersect(request.GetScopes()));

    foreach (var claim in principal.Claims)
    {
        claim.SetDestinations(GetDestinations(claim,principal));
    }

    return SignIn(principal,OpenIddictServerAspNetCoreDefaults.AuthenticationScheme);
}

private IEnumerable<string> GetDestinations(Claim claim,ClaimsPrincipal principal)
{
    switch (claim.Type)
    {
        case OpenIddictConstants.Claims.Name:
            yield return OpenIddictConstants.Destinations.Accesstoken;

            if (principal.HasScope(OpenIddictConstants.Scopes.Profile))
                yield return OpenIddictConstants.Destinations.IdentityToken;

            yield break;

        case OpenIddictConstants.Claims.Email:
            yield return OpenIddictConstants.Destinations.Accesstoken;

            if (principal.HasScope(OpenIddictConstants.Scopes.Email))
                yield return OpenIddictConstants.Destinations.IdentityToken;

            yield break;

        case OpenIddictConstants.Claims.Role:
            yield return OpenIddictConstants.Destinations.Accesstoken;

            if (principal.HasScope(OpenIddictConstants.Scopes.Roles))
                yield return OpenIddictConstants.Destinations.IdentityToken;

            yield break;

        case "AspNet.Identity.SecurityStamp": yield break;

        default:
            yield return OpenIddictConstants.Destinations.Accesstoken;
            yield break;
    }
}

大部分代码来自 OpenIddict 的示例。

我真的不明白这是怎么回事

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)