mirror of https://github.com/abpframework/abp.git
7 changed files with 67 additions and 95 deletions
@ -0,0 +1,17 @@ |
|||
using System.Net.Http; |
|||
using System.Threading.Tasks; |
|||
using JetBrains.Annotations; |
|||
|
|||
namespace Volo.Abp.IdentityModel |
|||
{ |
|||
//TODO: Re-consider this interface!
|
|||
public interface IIdentityModelAuthenticationService |
|||
{ |
|||
Task<bool> TryAuthenticateAsync( |
|||
[NotNull] HttpClient client, |
|||
string identityClientName = null); |
|||
|
|||
Task<string> GetAccessTokenAsync( |
|||
IdentityClientConfiguration configuration); |
|||
} |
|||
} |
|||
@ -1,9 +0,0 @@ |
|||
using System.Threading.Tasks; |
|||
|
|||
namespace Volo.Abp.IdentityModel |
|||
{ |
|||
public interface IIdentityModelHttpClientAuthenticator |
|||
{ |
|||
Task AuthenticateAsync(IdentityModelHttpClientAuthenticateContext context); |
|||
} |
|||
} |
|||
@ -1,78 +1,89 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Net.Http.Headers; |
|||
using System.Threading.Tasks; |
|||
using IdentityModel; |
|||
using IdentityModel; |
|||
using IdentityModel.Client; |
|||
using JetBrains.Annotations; |
|||
using Microsoft.Extensions.Logging; |
|||
using Microsoft.Extensions.Logging.Abstractions; |
|||
using Microsoft.Extensions.Options; |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Net.Http; |
|||
using System.Net.Http.Headers; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.DependencyInjection; |
|||
|
|||
namespace Volo.Abp.IdentityModel |
|||
{ |
|||
[Dependency(ReplaceServices = true)] |
|||
public class IdentityModelHttpClientAuthenticator : IIdentityModelHttpClientAuthenticator, ITransientDependency |
|||
public class IdentityModelAuthenticationService : IIdentityModelAuthenticationService, ITransientDependency |
|||
{ |
|||
public ILogger<IdentityModelHttpClientAuthenticator> Logger { get; set; } |
|||
public ILogger<IdentityModelAuthenticationService> Logger { get; set; } |
|||
protected IdentityClientOptions ClientOptions { get; } |
|||
|
|||
public IdentityModelHttpClientAuthenticator( |
|||
|
|||
public IdentityModelAuthenticationService( |
|||
IOptions<IdentityClientOptions> options) |
|||
{ |
|||
ClientOptions = options.Value; |
|||
Logger = NullLogger<IdentityModelHttpClientAuthenticator>.Instance; |
|||
Logger = NullLogger<IdentityModelAuthenticationService>.Instance; |
|||
} |
|||
|
|||
public async Task AuthenticateAsync(IdentityModelHttpClientAuthenticateContext context) |
|||
public async Task<bool> TryAuthenticateAsync( |
|||
[NotNull] HttpClient client, |
|||
string identityClientName = null) |
|||
{ |
|||
var accessToken = await GetAccessTokenFromServerOrNullAsync(context); |
|||
|
|||
if (accessToken != null) |
|||
var accessToken = await GetAccessTokenOrNullAsync(identityClientName); |
|||
if (accessToken == null) |
|||
{ |
|||
//TODO: "Bearer" should be configurable
|
|||
context.Client.DefaultRequestHeaders.Authorization |
|||
= new AuthenticationHeaderValue("Bearer", accessToken); |
|||
return false; |
|||
} |
|||
} |
|||
|
|||
protected virtual async Task<string> GetAccessTokenFromServerOrNullAsync(IdentityModelHttpClientAuthenticateContext context) |
|||
{ |
|||
//TODO: Better logging
|
|||
SetAccessToken(client, accessToken); |
|||
return true; |
|||
|
|||
var configuration = GetClientConfiguration(context); |
|||
} |
|||
|
|||
protected virtual async Task<string> GetAccessTokenOrNullAsync(string identityClientName) |
|||
{ |
|||
var configuration = GetClientConfiguration(identityClientName); |
|||
if (configuration == null) |
|||
{ |
|||
Logger.LogWarning($"Could not find {nameof(IdentityClientConfiguration)} for {context.IdentityClientName}. Either define a configuration for {context.IdentityClientName} or set a default configuration."); |
|||
Logger.LogWarning($"Could not find {nameof(IdentityClientConfiguration)} for {identityClientName}. Either define a configuration for {identityClientName} or set a default configuration."); |
|||
return null; |
|||
} |
|||
|
|||
return await GetAccessTokenAsync(configuration); |
|||
} |
|||
|
|||
public virtual async Task<string> GetAccessTokenAsync(IdentityClientConfiguration configuration) |
|||
{ |
|||
var discoveryResponse = await GetDiscoveryResponse(configuration); |
|||
if (discoveryResponse.IsError) |
|||
{ |
|||
Logger.LogError($"Could not retrieve the OpenId Connect discovery document! ErrorType: {discoveryResponse.ErrorType}. Error: {discoveryResponse.Error}"); |
|||
return null; |
|||
throw new AbpException($"Could not retrieve the OpenId Connect discovery document! ErrorType: {discoveryResponse.ErrorType}. Error: {discoveryResponse.Error}"); |
|||
} |
|||
|
|||
var tokenResponse = await GetTokenResponse(discoveryResponse, configuration); |
|||
if (tokenResponse.IsError) |
|||
{ |
|||
Logger.LogError($"Could not get token from the OpenId Connect server! ErrorType: {tokenResponse.ErrorType}. Error: {tokenResponse.Error}. ErrorDescription: {tokenResponse.ErrorDescription}. HttpStatusCode: {tokenResponse.HttpStatusCode}"); |
|||
return null; |
|||
throw new AbpException($"Could not get token from the OpenId Connect server! ErrorType: {tokenResponse.ErrorType}. Error: {tokenResponse.Error}. ErrorDescription: {tokenResponse.ErrorDescription}. HttpStatusCode: {tokenResponse.HttpStatusCode}"); |
|||
} |
|||
|
|||
return tokenResponse.AccessToken; |
|||
} |
|||
|
|||
private IdentityClientConfiguration GetClientConfiguration(IdentityModelHttpClientAuthenticateContext context) |
|||
protected virtual void SetAccessToken(HttpClient client, string accessToken) |
|||
{ |
|||
//TODO: "Bearer" should be configurable
|
|||
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken); |
|||
} |
|||
|
|||
private IdentityClientConfiguration GetClientConfiguration(string identityClientName = null) |
|||
{ |
|||
if (context.IdentityClientName.IsNullOrEmpty()) |
|||
if (identityClientName.IsNullOrEmpty()) |
|||
{ |
|||
return ClientOptions.IdentityClients.Default; |
|||
} |
|||
|
|||
return ClientOptions.IdentityClients.GetOrDefault(context.IdentityClientName) ?? |
|||
return ClientOptions.IdentityClients.GetOrDefault(identityClientName) ?? |
|||
ClientOptions.IdentityClients.Default; |
|||
} |
|||
|
|||
@ -1,25 +0,0 @@ |
|||
using System.Net.Http; |
|||
using JetBrains.Annotations; |
|||
|
|||
namespace Volo.Abp.IdentityModel |
|||
{ |
|||
public class IdentityModelHttpClientAuthenticateContext |
|||
{ |
|||
public HttpClient Client { get; } |
|||
|
|||
/// <summary>
|
|||
/// The identity client name configured with the <see cref="IdentityClientOptions"/>.
|
|||
/// </summary>
|
|||
public string IdentityClientName { get; } |
|||
|
|||
/// <param name="client"><see cref="HttpClient"/> object to be authenticated</param>
|
|||
/// <param name="identityClientName">The identity client name configured with the <see cref="IdentityClientOptions"/>.</param>
|
|||
public IdentityModelHttpClientAuthenticateContext( |
|||
[NotNull] HttpClient client, |
|||
string identityClientName = null) |
|||
{ |
|||
Client = Check.NotNull(client, nameof(client)); |
|||
IdentityClientName = identityClientName; |
|||
} |
|||
} |
|||
} |
|||
@ -1,27 +0,0 @@ |
|||
using System.Net.Http; |
|||
using System.Threading.Tasks; |
|||
using JetBrains.Annotations; |
|||
|
|||
namespace Volo.Abp.IdentityModel |
|||
{ |
|||
public static class IdentityModelHttpClientAuthenticatorExtensions |
|||
{ |
|||
/// <param name="authenticator">Authenticator object</param>
|
|||
/// <param name="client"><see cref="HttpClient"/> object to be authenticated</param>
|
|||
/// <param name="identityClientName">The identity client name configured with the <see cref="IdentityClientOptions"/>.</param>
|
|||
public static Task AuthenticateAsync( |
|||
[NotNull] this IIdentityModelHttpClientAuthenticator authenticator, |
|||
[NotNull] HttpClient client, |
|||
string identityClientName = null) |
|||
{ |
|||
Check.NotNull(authenticator, nameof(authenticator)); |
|||
|
|||
return authenticator.AuthenticateAsync( |
|||
new IdentityModelHttpClientAuthenticateContext( |
|||
client, |
|||
identityClientName |
|||
) |
|||
); |
|||
} |
|||
} |
|||
} |
|||
Loading…
Reference in new issue