OAuth 2.0为令牌端点定义了标准授权类型,例如password
,authorization_code
和refresh_token
。扩展授权是一种添加对非标准令牌颁发方案(如令牌转换,委派或自定义凭据)的支持的方法。
您可以通过实现IExtensionGrantValidato
r接口添加对其他授权类型的支持:
public interface IExtensionGrantValidator
{
/// <summary>
/// Handles the custom grant request.
/// </summary>
/// <param name="request">The validation context.</param>
Task ValidateAsync(ExtensionGrantValidationContext context);
/// <summary>
/// Returns the grant type this validator can deal with
/// </summary>
/// <value>
/// The type of the grant.
/// </value>
string GrantType { get; }
}
该ExtensionGrantValidationContext
对象使您可以访问:
- 传入令牌请求 - 众所周知的验证值,以及任何自定义值(通过
Raw
集合) - 结果 - 错误或成功
- 自定义响应参数
要注册扩展授权,请将其添加到DI:
builder.AddExtensionGrantValidator<MyExtensionsGrantValidator>();
36.1 示例:使用扩展授权的简单委派
想象一下以下场景 - 前端客户端使用通过交互流(例如混合流)获取的令牌调用中间层API。此中间层API(API 1)现在希望代表交互式用户调用后端API(API 2):
换句话说,中间层API(API 1)需要包含用户身份的访问令牌,但需要具有后端API(API 2)的范围。
注意
您可能听说过穷人代表团这一术语,前端的访问令牌只是转发到后端。这有一些缺点,例如API 2现在必须接受API 1范围,这将允许用户直接调用API 2。此外 - 您可能希望在令牌中添加一些特定于委托的声明,例如,调用路径是通过API 1的事实。
36.1.1 实现扩展授权
前端会将令牌发送到API 1,现在需要在IdentityServer上使用API 2的新令牌交换此令牌。
在线上,对交换的令牌服务的调用可能如下所示:
POST /connect/token
grant_type=delegation&
scope=api2&
token=...&
client_id=api1.client
client_secret=secret
扩展授权验证程序的工作是通过验证传入令牌来处理该请求,并返回表示新令牌的结果:
public class DelegationGrantValidator : IExtensionGrantValidator
{
private readonly ITokenValidator _validator;
public DelegationGrantValidator(ITokenValidator validator)
{
_validator = validator;
}
public string GrantType => "delegation";
public async Task ValidateAsync(ExtensionGrantValidationContext context)
{
var userToken = context.Request.Raw.Get("token");
if (string.IsNullOrEmpty(userToken))
{
context.Result = new GrantValidationResult(TokenRequestErrors.InvalidGrant);
return;
}
var result = await _validator.ValidateAccessTokenAsync(userToken);
if (result.IsError)
{
context.Result = new GrantValidationResult(TokenRequestErrors.InvalidGrant);
return;
}
// get user's identity
var sub = result.Claims.FirstOrDefault(c => c.Type == "sub").Value;
context.Result = new GrantValidationResult(sub, GrantType);
return;
}
}
不要忘记在DI上注册验证器。
36.1.2 注册委托客户端
您需要在IdentityServer中进行客户端注册,以允许客户端使用此新的扩展授权,例如:
var client = new client
{
ClientId = "api1.client",
ClientSecrets = new List<Secret>
{
new Secret("secret".Sha256())
},
AllowedGrantTypes = { "delegation" },
AllowedScopes = new List<string>
{
"api2"
}
}
36.1.3 调用令牌端点
在API 1中,您现在可以自己构建HTTP有效内容,或使用IdentityModel帮助程序库:
public async Task<TokenResponse> DelegateAsync(string userToken)
{
var payload = new
{
token = userToken
};
// create token client
var client = new TokenClient(disco.TokenEndpoint, "api1.client", "secret");
// send custom grant to token endpoint, return response
return await client.RequestCustomGrantAsync("delegation", "api2", payload);
}
现在TokenResponse.AccessToken
将包含委托访问令牌。