如何将自定义身份验证提供程序集成到IdentityServer4中

时间:2017-05-05 16:35:05

标签: identityserver4

是否有可能以某种方式扩展IdentityServer4以运行自定义身份验证逻辑?我需要针对几个现有的自定义身份系统验证凭据,并且很难找到这样做的扩展点(他们使用自定义协议)。 所有这些现有系统都具有客户端知道的API密钥的概念。 IdentityServer作业现在应该验证此API密钥,并从系统中提取一些现有声明。 我想要做这样的事情:

POST /connect/token
    custom_provider_name=my_custom_provider_1&
    custom_provider_api_key=secret_api_key

然后我按逻辑调用my_custom_provider_1,验证API密钥,获取声明并将它们传递回IdentityServer流程以完成其余工作。

这可能吗?

1 个答案:

答案 0 :(得分:7)

我假设您可以控制客户端及其发出的请求,因此您可以对Identity Server进行适当的调用。

可以使用自定义身份验证逻辑,毕竟这是ResourceOwnerPassword流的全部内容:客户端将信息传递给Connect / token端点,然后编写代码到确定该信息的含义并确定这是否足以验证该客户端。尽管惯例说客户传递的信息是usernamepassword

你肯定会走出人们想要做的事情。

Startup.ConfigureServices中,您需要添加自己的IResourceOwnerPasswordValidator实现,有点像这样:

services.AddTransient<IResourceOwnerPasswordValidator, ResourceOwnerPasswordValidator>();

然后在该类的ValidateAsync方法中,您可以执行任何您喜欢的逻辑,以决定是将context.Result设置为成功的GrantValidationResult还是失败的ResourceOwnerPasswordValidationContext。可以帮助您完成该方法的一件事是,IExtensionGrantValidator可以访问原始请求。因此,您可以使用添加到连接/令牌端点的原始调用中的任何自定义字段。您可以在此处添加自定义字段(提供程序名称,API密钥等)。

祝你好运!

编辑:以上内容可行,但实际上是滥用标准的授权/流程。更好的是OP发现使用POST /connect/token grant_type=my_crap_grant& scope=my_desired_scope& rhubarb=true& custard=true& music=ska 接口来滚动您自己的授权类型和身份验证逻辑的方法。例如:

从客户端呼叫身份服务器:

services.AddTransient<IExtensionGrantValidator, MyCrapGrantValidator>();

使用DI注册您的分机拨款:

public class MyCrapGrantValidator : IExtensionGrantValidator
{
    // your custom grant needs a name, used in the Post to /connect/token
    public string GrantType => "my_crap_grant";

    public async Task ValidateAsync(ExtensionGrantValidationContext context)
    {
        // Get the values for the data you expect to be used for your custom grant type
        var rhubarb = context.Request.Raw.Get("rhubarb");
        var custard = context.Request.Raw.Get("custard");
        var music = context.Request.Raw.Get("music");

        if (string.IsNullOrWhiteSpace(rhubarb)||string.IsNullOrWhiteSpace(custard)||string.IsNullOrWhiteSpace(music)
        {
            // this request doesn't have the data we'd expect for our grant type
            context.Result = new     GrantValidationResult(TokenRequestErrors.InvalidGrant);
            return Task.FromResult(false);
        }

        // Do your logic to work out, based on the data provided, whether 
        // this request is valid or not
        if (bool.Parse(rhubarb) && bool.Parse(custard) && music=="ska")
        {
            // This grant gives access to any client that simply makes a 
            // request with rhubarb and custard both true, and has music 
            // equal to ska. You should do better and involve databases and 
            // other technical things
            var sub = "ThisIsNotGoodSub";
            context.Result = new GrantValidationResult(sub,"my_crap_grant");
            Task.FromResult(0);
        }

        // Otherwise they're unauthorised
        context.Result = new GrantValidationResult(TokenRequestErrors.UnauthorizedClient);
        return Task.FromResult(false);
    }
}

并实施您的授权验证工具:

<form id="myForm1">
//Other Code Here