如何将自定义身份验证提供程序集成到 IdentityServer4 中
How to integrate custom authentication provider into 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 流程以完成其余工作。
这可能吗?
我假设您可以控制客户端及其发出的请求,因此您可以对您的身份服务器进行适当的调用。
可以使用自定义身份验证逻辑,毕竟这就是 ResourceOwnerPassword
流程的全部内容:客户端将信息传递给 Connect/token 端点,然后您编写代码来确定该信息的含义,并确定这是否足以验证该客户端。不过,您肯定会另辟蹊径去做您想做的事,因为约定俗成,客户端传递的信息是 username
和 password
.
在您的 Startup.ConfigureServices
中,您需要添加自己的 IResourceOwnerPasswordValidator
实现,有点像这样:
services.AddTransient<IResourceOwnerPasswordValidator, ResourceOwnerPasswordValidator>();
然后在那个 class 的 ValidateAsync
方法中,你可以做任何你喜欢的逻辑来决定是将 context.Result
设置为成功的 GrantValidationResult
,还是一个失败了。在该方法中可以帮助您的一件事是 ResourceOwnerPasswordValidationContext
可以访问原始请求。因此,您添加到 connect/token 端点的原始调用中的任何自定义字段都将可供您使用。您可以在此处添加自定义字段(供应商名称、api 键等)。
祝你好运!
编辑:上面的方法可行,但实际上是在滥用标准 grant/flow。 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);
}
}
是否有可能以某种方式将 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 流程以完成其余工作。
这可能吗?
我假设您可以控制客户端及其发出的请求,因此您可以对您的身份服务器进行适当的调用。
可以使用自定义身份验证逻辑,毕竟这就是 ResourceOwnerPassword
流程的全部内容:客户端将信息传递给 Connect/token 端点,然后您编写代码来确定该信息的含义,并确定这是否足以验证该客户端。不过,您肯定会另辟蹊径去做您想做的事,因为约定俗成,客户端传递的信息是 username
和 password
.
在您的 Startup.ConfigureServices
中,您需要添加自己的 IResourceOwnerPasswordValidator
实现,有点像这样:
services.AddTransient<IResourceOwnerPasswordValidator, ResourceOwnerPasswordValidator>();
然后在那个 class 的 ValidateAsync
方法中,你可以做任何你喜欢的逻辑来决定是将 context.Result
设置为成功的 GrantValidationResult
,还是一个失败了。在该方法中可以帮助您的一件事是 ResourceOwnerPasswordValidationContext
可以访问原始请求。因此,您添加到 connect/token 端点的原始调用中的任何自定义字段都将可供您使用。您可以在此处添加自定义字段(供应商名称、api 键等)。
祝你好运!
编辑:上面的方法可行,但实际上是在滥用标准 grant/flow。 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);
}
}