【问题标题】:How to integrate custom authentication provider into IdentityServer4如何将自定义身份验证提供程序集成到 IdentityServer4
【发布时间】:2023-03-24 12:28:02
【问题描述】:

是否有可能以某种方式扩展 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 流以完成其余工作。

这可能吗?

【问题讨论】:

  • 除非他们使用标准协议(openid connect、oauth),否则您将无法将现有客户端与身份服务器一起使用。
  • 你最后搞定了吗?如果是这样,请分享你是如何做到的。

标签: identityserver4


【解决方案1】:

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

可以使用自定义身份验证逻辑,毕竟这就是 ResourceOwnerPassword 流程的全部意义所在:客户端将信息传递给 Connect/token 端点,然后您编写代码来决定什么该信息意味着并决定这是否足以验证该客户端。不过,您肯定会偏离常规去做您想做的事,因为惯例规定客户传递的信息是 usernamepassword

在您的Startup.ConfigureServices 中,您需要添加自己的IResourceOwnerPasswordValidator 实现,如下所示:

services.AddTransient<IResourceOwnerPasswordValidator, ResourceOwnerPasswordValidator>();

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

祝你好运!

编辑:上述方法可行,但实际上是在滥用标准授权/流程。 OP 发现的使用IExtensionGrantValidator 接口来滚动您自己的授权类型和身份验证逻辑的方法要好得多。例如:

从客户端调用身份服务器:

POST /connect/token
grant_type=my_crap_grant&
scope=my_desired_scope&
rhubarb=true&
custard=true&
music=ska

向 DI 注册您的延期拨款:

services.AddTransient<IExtensionGrantValidator, MyCrapGrantValidator>();

并实施您的授权验证器:

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

【讨论】:

  • 非常感谢,IResourceOwnerPasswordValidator 按描述工作。但是,我还发现 IExtensionGrantValidator 也可以通过为每个身份验证提供程序定义自定义授权类型并在调用 RequestCustomGrantAsync 时将 api 密钥传递给额外的对象来正常工作。不知何故,这对我的场景来说感觉更自然,因为我不必滥用用户名/密码字段。这样做可以吗?
  • 是的,这看起来是一种更好的方法,而不是滥用 password 授权类型
  • @NKnusperer:您能否提供您的解决方案或至少提供基本步骤?我有类似的情况,我不知道如何使用 IExtensionGrantValidator。提前非常感谢!
  • @user4587483 查看我的编辑以获取实现IExtensionGrantValidator 的(废话)示例
  • IExtensionGrantValidator 是否仍然推荐使用最新的 IS4 执行此操作?
猜你喜欢
  • 2012-04-05
  • 1970-01-01
  • 2012-11-09
  • 2013-10-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-11-15
  • 2020-07-23
相关资源
最近更新 更多