IdentityServer 4-自定义IExtensionGrantValidator始终返回invalid_grant

时间:2019-08-11 14:28:05

标签: asp.net-core identityserver4

我的应用程序要求使用客户端凭据和其他代码(哈希)进行身份验证。 我遵循此link来创建和使用自定义IExtensionGrantValidator。 我设法通过批准的授权来调用自定义IExtensionGrantValidator,但是客户总是会遇到invalid_grant错误。

由于某种原因,d Result(属性ExtensionGrantValidationContext)的设置操作总是失败(覆盖Error值会将覆盖的值返回给客户端)。

这是CustomGrantValidator代码:

public class CustomGrantValidator : IExtensionGrantValidator
{
    public string GrantType => "grant-name";

    public Task ValidateAsync(ExtensionGrantValidationContext context)
    {
        var hash = context.Request.Raw["hash"]; //extract hash from request
        var result = string.IsNullOrEmpty(hash) ?
            new GrantValidationResult(TokenRequestErrors.InvalidRequest) :
            new GrantValidationResult(hash, GrantType);
        context.Result = result
    }
}

Startup.cs包含以下行:

services.AddTransient<IExtensionGrantValidator, CustomGrantValidator>();

最后是客户的代码:

        var httpClient = new HttpClient() { BaseAddress = new Uri("http://localhost:5000") };
        var disco = await httpClient.GetDiscoveryDocumentAsync("http://localhost:5000");

        var cReq = await httpClient.RequestTokenAsync(new TokenRequest
        {
            GrantType = "grant-name",
            Address = disco.TokenEndpoint,

            ClientId = clientId,// client Id taken from appsetting.json
            ClientSecret = clientSecret, //client secret taken from appsetting.json
            Parameters = new Dictionary<string, string> { { "hash", hash } }
        });

        if (cReq.IsError)
            //always getting 'invalid_grant' error
            throw InvalidOperationException($"{cReq.Error}: {cReq.ErrorDescription}");

2 个答案:

答案 0 :(得分:0)

以下代码适用于我的环境:

public async  Task ValidateAsync(ExtensionGrantValidationContext context)
{
    var hash = context.Request.Raw["hash"]; //extract hash from request
    var result = string.IsNullOrEmpty(hash) ?
        new GrantValidationResult(TokenRequestErrors.InvalidRequest) :
        new GrantValidationResult(hash, GrantType);
    context.Result = result;

    return;
}

不要忘记注册客户端以允许自定义授予:

return new List<Client>
    {
        new Client
        {
            ClientId = "client",

            // no interactive user, use the clientid/secret for authentication
            AllowedGrantTypes = { "grant-name" },

            // secret for authentication
            ClientSecrets =
            {
                new Secret("secret".Sha256())
            },

            // scopes that client has access to
            AllowedScopes = { "api1" }
        }
    };

答案 1 :(得分:0)

我遇到了同样的问题,并从@Sarah Lissachell 找到了答案,结果证明我需要实现 IProfileService。这个接口有一个叫做 IsActiveAsync 的方法。如果不实现这个方法,ValidateAsync 的答案永远是false。

public class IdentityProfileService : IProfileService
{

    //This method comes second
    public async Task GetProfileDataAsync(ProfileDataRequestContext context)
    {
        //IsActiveAsync turns out to be true 
        //Here you add the claims that you want in the access token
        var claims = new List<Claim>();

        claims.Add(new Claim("ThisIsNotAGoodClaim", "MyCrapClaim"));

        context.IssuedClaims = claims;
    }

    //This method comes first
    public async Task IsActiveAsync(IsActiveContext context)
    {           
        bool isActive = false;
        /*
            Implement some code to determine that the user is actually active 
            and set isActive to true
        */
        context.IsActive = isActive;
    }
}

然后你必须在你的启动页面中添加这个实现。

public void ConfigureServices(IServiceCollection services)
{

    // Some other code
    services.AddIdentityServer()
                .AddDeveloperSigningCredential()
                .AddAspNetIdentity<Users>()
                .AddInMemoryApiResources(config.GetApiResources())
                .AddExtensionGrantValidator<CustomGrantValidator>()
                .AddProfileService<IdentityProfileService>();
    // More code
}