mirror of https://github.com/abpframework/abp.git
committed by
GitHub
6 changed files with 242 additions and 0 deletions
@ -0,0 +1,129 @@ |
|||
# How to add a custom grant type in OpenIddict |
|||
|
|||
## ITokenExtensionGrant |
|||
|
|||
Create a class that inherits `ITokenExtensionGrant`, and then register it with the framework. |
|||
|
|||
In the `MyTokenExtensionGrant` class below we try to get the token details, The `ForbidResult` handles the failure case and `SignInResult` returns a new token response, You can pass more parameters to implement business checks. |
|||
|
|||
```cs |
|||
public class MyTokenExtensionGrant : ITokenExtensionGrant |
|||
{ |
|||
public const string ExtensionGrantName = "MyTokenExtensionGrant"; |
|||
|
|||
public string Name => ExtensionGrantName; |
|||
public async Task<IActionResult> HandleAsync(ExtensionGrantContext context) |
|||
{ |
|||
var userToken = context.Request.GetParameter("token").ToString(); |
|||
|
|||
if (string.IsNullOrEmpty(userToken)) |
|||
{ |
|||
return new ForbidResult( |
|||
new[] {OpenIddictServerAspNetCoreDefaults.AuthenticationScheme}, |
|||
properties: new AuthenticationProperties(new Dictionary<string, string> |
|||
{ |
|||
[OpenIddictServerAspNetCoreConstants.Properties.Error] = OpenIddictConstants.Errors.InvalidRequest |
|||
}!)); |
|||
} |
|||
|
|||
var transaction = await context.HttpContext.RequestServices.GetRequiredService<IOpenIddictServerFactory>().CreateTransactionAsync(); |
|||
transaction.EndpointType = OpenIddictServerEndpointType.Introspection; |
|||
transaction.Request = new OpenIddictRequest |
|||
{ |
|||
ClientId = context.Request.ClientId, |
|||
ClientSecret = context.Request.ClientSecret, |
|||
Token = userToken |
|||
}; |
|||
|
|||
var notification = new OpenIddictServerEvents.ProcessAuthenticationContext(transaction); |
|||
var dispatcher = context.HttpContext.RequestServices.GetRequiredService<IOpenIddictServerDispatcher>(); |
|||
await dispatcher.DispatchAsync(notification); |
|||
|
|||
if (notification.IsRejected) |
|||
{ |
|||
return new ForbidResult( |
|||
new []{ OpenIddictServerAspNetCoreDefaults.AuthenticationScheme }, |
|||
properties: new AuthenticationProperties(new Dictionary<string, string> |
|||
{ |
|||
[OpenIddictServerAspNetCoreConstants.Properties.Error] = notification.Error ?? OpenIddictConstants.Errors.InvalidRequest, |
|||
[OpenIddictServerAspNetCoreConstants.Properties.ErrorDescription] = notification.ErrorDescription, |
|||
[OpenIddictServerAspNetCoreConstants.Properties.ErrorUri] = notification.ErrorUri |
|||
})); |
|||
} |
|||
|
|||
var principal = notification.GenericTokenPrincipal; |
|||
if (principal == null) |
|||
{ |
|||
return new ForbidResult( |
|||
new []{ OpenIddictServerAspNetCoreDefaults.AuthenticationScheme }, |
|||
properties: new AuthenticationProperties(new Dictionary<string, string> |
|||
{ |
|||
[OpenIddictServerAspNetCoreConstants.Properties.Error] = notification.Error ?? OpenIddictConstants.Errors.InvalidRequest, |
|||
[OpenIddictServerAspNetCoreConstants.Properties.ErrorDescription] = notification.ErrorDescription, |
|||
[OpenIddictServerAspNetCoreConstants.Properties.ErrorUri] = notification.ErrorUri |
|||
})); |
|||
} |
|||
|
|||
var userId = principal.FindUserId(); |
|||
var userManager = context.HttpContext.RequestServices.GetRequiredService<IdentityUserManager>(); |
|||
var user = await userManager.GetByIdAsync(userId.Value); |
|||
var userClaimsPrincipalFactory = context.HttpContext.RequestServices.GetRequiredService<IUserClaimsPrincipalFactory<IdentityUser>>(); |
|||
var claimsPrincipal = await userClaimsPrincipalFactory.CreateAsync(user); |
|||
claimsPrincipal.SetScopes(principal.GetScopes()); |
|||
claimsPrincipal.SetResources(await GetResourcesAsync(context, principal.GetScopes())); |
|||
await context.HttpContext.RequestServices.GetRequiredService<AbpOpenIddictClaimDestinationsManager>().SetAsync(principal); |
|||
return new SignInResult(OpenIddictServerAspNetCoreDefaults.AuthenticationScheme, claimsPrincipal); |
|||
} |
|||
|
|||
private async Task<IEnumerable<string>> GetResourcesAsync(ExtensionGrantContext context, ImmutableArray<string> scopes) |
|||
{ |
|||
var resources = new List<string>(); |
|||
if (!scopes.Any()) |
|||
{ |
|||
return resources; |
|||
} |
|||
|
|||
await foreach (var resource in context.HttpContext.RequestServices.GetRequiredService<IOpenIddictScopeManager>().ListResourcesAsync(scopes)) |
|||
{ |
|||
resources.Add(resource); |
|||
} |
|||
return resources; |
|||
} |
|||
} |
|||
``` |
|||
|
|||
```cs |
|||
public override void PreConfigureServices(ServiceConfigurationContext context) |
|||
{ |
|||
//... |
|||
PreConfigure<OpenIddictServerBuilder>(builder => |
|||
{ |
|||
builder.Configure(openIddictServerOptions => |
|||
{ |
|||
openIddictServerOptions.GrantTypes.Add(MyTokenExtensionGrant.ExtensionGrantName); |
|||
}); |
|||
}); |
|||
//... |
|||
} |
|||
|
|||
public override void ConfigureServices(ServiceConfigurationContext context) |
|||
{ |
|||
//... |
|||
Configure<AbpOpenIddictExtensionGrantsOptions>(options => |
|||
{ |
|||
options.Grants.Add(MyTokenExtensionGrant.ExtensionGrantName, new MyTokenExtensionGrant()); |
|||
}); |
|||
//... |
|||
} |
|||
``` |
|||
|
|||
|
|||
 |
|||
|
|||
 |
|||
|
|||
## Source code |
|||
|
|||
https://github.com/abpframework/abp/commit/3210f138454697647689b4868c8d4b7b3da02d44 |
|||
|
|||
|
|||
|
After Width: | Height: | Size: 422 KiB |
|
After Width: | Height: | Size: 425 KiB |
@ -0,0 +1,99 @@ |
|||
using System.Collections.Immutable; |
|||
using System.Security.Principal; |
|||
using Microsoft.AspNetCore.Authentication; |
|||
using Microsoft.AspNetCore.Identity; |
|||
using Microsoft.AspNetCore.Mvc; |
|||
using OpenIddict.Abstractions; |
|||
using OpenIddict.Server; |
|||
using OpenIddict.Server.AspNetCore; |
|||
using Volo.Abp.Identity; |
|||
using Volo.Abp.OpenIddict; |
|||
using Volo.Abp.OpenIddict.ExtensionGrantTypes; |
|||
using IdentityUser = Volo.Abp.Identity.IdentityUser; |
|||
using SignInResult = Microsoft.AspNetCore.Mvc.SignInResult; |
|||
|
|||
namespace OpenIddict.Demo.Server.ExtensionGrants; |
|||
|
|||
public class MyTokenExtensionGrant : ITokenExtensionGrant |
|||
{ |
|||
public const string ExtensionGrantName = "MyTokenExtensionGrant"; |
|||
|
|||
public string Name => ExtensionGrantName; |
|||
public async Task<IActionResult> HandleAsync(ExtensionGrantContext context) |
|||
{ |
|||
var userToken = context.Request.GetParameter("token").ToString(); |
|||
|
|||
if (string.IsNullOrEmpty(userToken)) |
|||
{ |
|||
return new ForbidResult( |
|||
new[] {OpenIddictServerAspNetCoreDefaults.AuthenticationScheme}, |
|||
properties: new AuthenticationProperties(new Dictionary<string, string> |
|||
{ |
|||
[OpenIddictServerAspNetCoreConstants.Properties.Error] = OpenIddictConstants.Errors.InvalidRequest |
|||
}!)); |
|||
} |
|||
|
|||
var transaction = await context.HttpContext.RequestServices.GetRequiredService<IOpenIddictServerFactory>().CreateTransactionAsync(); |
|||
transaction.EndpointType = OpenIddictServerEndpointType.Introspection; |
|||
transaction.Request = new OpenIddictRequest |
|||
{ |
|||
ClientId = context.Request.ClientId, |
|||
ClientSecret = context.Request.ClientSecret, |
|||
Token = userToken |
|||
}; |
|||
|
|||
var notification = new OpenIddictServerEvents.ProcessAuthenticationContext(transaction); |
|||
var dispatcher = context.HttpContext.RequestServices.GetRequiredService<IOpenIddictServerDispatcher>(); |
|||
await dispatcher.DispatchAsync(notification); |
|||
|
|||
if (notification.IsRejected) |
|||
{ |
|||
return new ForbidResult( |
|||
new []{ OpenIddictServerAspNetCoreDefaults.AuthenticationScheme }, |
|||
properties: new AuthenticationProperties(new Dictionary<string, string> |
|||
{ |
|||
[OpenIddictServerAspNetCoreConstants.Properties.Error] = notification.Error ?? OpenIddictConstants.Errors.InvalidRequest, |
|||
[OpenIddictServerAspNetCoreConstants.Properties.ErrorDescription] = notification.ErrorDescription, |
|||
[OpenIddictServerAspNetCoreConstants.Properties.ErrorUri] = notification.ErrorUri |
|||
})); |
|||
} |
|||
|
|||
var principal = notification.GenericTokenPrincipal; |
|||
if (principal == null) |
|||
{ |
|||
return new ForbidResult( |
|||
new []{ OpenIddictServerAspNetCoreDefaults.AuthenticationScheme }, |
|||
properties: new AuthenticationProperties(new Dictionary<string, string> |
|||
{ |
|||
[OpenIddictServerAspNetCoreConstants.Properties.Error] = notification.Error ?? OpenIddictConstants.Errors.InvalidRequest, |
|||
[OpenIddictServerAspNetCoreConstants.Properties.ErrorDescription] = notification.ErrorDescription, |
|||
[OpenIddictServerAspNetCoreConstants.Properties.ErrorUri] = notification.ErrorUri |
|||
})); |
|||
} |
|||
|
|||
var userId = principal.FindUserId(); |
|||
var userManager = context.HttpContext.RequestServices.GetRequiredService<IdentityUserManager>(); |
|||
var user = await userManager.GetByIdAsync(userId.Value); |
|||
var userClaimsPrincipalFactory = context.HttpContext.RequestServices.GetRequiredService<IUserClaimsPrincipalFactory<IdentityUser>>(); |
|||
var claimsPrincipal = await userClaimsPrincipalFactory.CreateAsync(user); |
|||
claimsPrincipal.SetScopes(principal.GetScopes()); |
|||
claimsPrincipal.SetResources(await GetResourcesAsync(context, principal.GetScopes())); |
|||
await context.HttpContext.RequestServices.GetRequiredService<AbpOpenIddictClaimDestinationsManager>().SetAsync(principal); |
|||
return new SignInResult(OpenIddictServerAspNetCoreDefaults.AuthenticationScheme, claimsPrincipal); |
|||
} |
|||
|
|||
private async Task<IEnumerable<string>> GetResourcesAsync(ExtensionGrantContext context, ImmutableArray<string> scopes) |
|||
{ |
|||
var resources = new List<string>(); |
|||
if (!scopes.Any()) |
|||
{ |
|||
return resources; |
|||
} |
|||
|
|||
await foreach (var resource in context.HttpContext.RequestServices.GetRequiredService<IOpenIddictScopeManager>().ListResourcesAsync(scopes)) |
|||
{ |
|||
resources.Add(resource); |
|||
} |
|||
return resources; |
|||
} |
|||
} |
|||
Loading…
Reference in new issue