Skip to content

Commit

Permalink
feat(stack sdk)/stack sdk caller (#508)
Browse files Browse the repository at this point in the history
* feat:stack sdk authentication

* refactor:rename Authentication.BlazorServer to Authentication.Universal

* feat:code format

* rename:Universal to Standard

* feat:udpate default token provider

* fix:token provider

* fix:pr
  • Loading branch information
MayueCif authored Mar 22, 2023
1 parent 679b50d commit c300f24
Show file tree
Hide file tree
Showing 26 changed files with 88 additions and 48 deletions.
4 changes: 2 additions & 2 deletions Masa.Framework.sln
Original file line number Diff line number Diff line change
Expand Up @@ -549,7 +549,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Globalization", "Globalizat
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{8D7D3D21-86DB-4FCC-8FF0-6E1587ABD22A}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Masa.Contrib.Service.Caller.Authentication.BlazorServer.Tests", "src\Contrib\Service\Caller\Authentication\Tests\Masa.Contrib.Service.Caller.Authentication.BlazorServer.Tests\Masa.Contrib.Service.Caller.Authentication.BlazorServer.Tests.csproj", "{BEA8E5A5-E7BD-4165-80CD-D1F53ED82D02}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Masa.Contrib.Service.Caller.Authentication.Standard.Tests", "src\Contrib\Service\Caller\Authentication\Tests\Masa.Contrib.Service.Caller.Authentication.Standard.Tests\Masa.Contrib.Service.Caller.Authentication.Standard.Tests.csproj", "{BEA8E5A5-E7BD-4165-80CD-D1F53ED82D02}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Masa.Contrib.Authentication.OpenIdConnect.EFCore.Oracle", "src\Contrib\Authentication\OpenIdConnect\Masa.Contrib.Authentication.OpenIdConnect.EFCore.Oracle\Masa.Contrib.Authentication.OpenIdConnect.EFCore.Oracle.csproj", "{03F476EF-022A-4370-B1C3-FEEDE3BB4E7F}"
EndProject
Expand Down Expand Up @@ -669,7 +669,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Masa.Contrib.Service.Caller
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Extensions", "Extensions", "{69BD70CA-62D8-4900-B781-4368C738B3EB}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Masa.Contrib.Service.Caller.Authentication.BlazorServer", "src\Contrib\Service\Caller\Authentication\Masa.Contrib.Service.Caller.Authentication.BlazorServer\Masa.Contrib.Service.Caller.Authentication.BlazorServer.csproj", "{3019BEEA-D141-4909-84A2-DC8852FF05EF}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Masa.Contrib.Service.Caller.Authentication.Standard", "src\Contrib\Service\Caller\Authentication\Masa.Contrib.Service.Caller.Authentication.Standard\Masa.Contrib.Service.Caller.Authentication.Standard.csproj", "{3019BEEA-D141-4909-84A2-DC8852FF05EF}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Masa.Contrib.Service.Caller.Authentication.AspNetCore.Tests", "src\Contrib\Service\Caller\Authentication\Tests\Masa.Contrib.Service.Caller.Authentication.AspNetCore.Tests\Masa.Contrib.Service.Caller.Authentication.AspNetCore.Tests.csproj", "{A95600A9-01A5-438A-A3FA-85A1B261C6A0}"
EndProject
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Copyright (c) MASA Stack All rights reserved.
// Licensed under the MIT License. See LICENSE.txt in the project root for license information.

namespace Masa.Contrib.Service.Caller.Authentication.BlazorServer;
namespace Masa.Contrib.Service.Caller.Authentication.Standard;

public class AuthenticationService : IAuthenticationService
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@ namespace Masa.BuildingBlocks.Service.Caller;

public static class MasaCallerClientBuilderExtensions
{
public static IMasaCallerClientBuilder UseAuthentication(
this IMasaCallerClientBuilder masaCallerClientBuilder)
{
return UseAuthentication(masaCallerClientBuilder, (serviceProvider) => { return new TokenProvider(); });
}

/// <summary>
/// Caller adds default authentication
/// </summary>
Expand All @@ -15,9 +21,10 @@ public static class MasaCallerClientBuilderExtensions
/// <returns></returns>
public static IMasaCallerClientBuilder UseAuthentication(
this IMasaCallerClientBuilder masaCallerClientBuilder,
Func<IServiceProvider, TokenProvider> tokenProvider,
string defaultScheme = AuthenticationConstant.DEFAULT_SCHEME)
{
masaCallerClientBuilder.Services.TryAddScoped<TokenProvider>();
masaCallerClientBuilder.Services.TryAddScoped((serviceProvider) => { return tokenProvider.Invoke(serviceProvider); });
masaCallerClientBuilder.UseAuthentication(serviceProvider =>
new AuthenticationService(
serviceProvider.GetRequiredService<TokenProvider>(),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
// Copyright (c) MASA Stack All rights reserved.
// Copyright (c) MASA Stack All rights reserved.
// Licensed under the MIT License. See LICENSE.txt in the project root for license information.

[assembly: InternalsVisibleTo("Masa.Contrib.Service.Caller.Authentication.BlazorServer.Tests")]
[assembly: InternalsVisibleTo("Masa.Contrib.Service.Caller.Authentication.Standard.Tests")]

// ReSharper disable once CheckNamespace

namespace Masa.Contrib.Service.Caller.Authentication.BlazorServer;
namespace Masa.Contrib.Service.Caller.Authentication.Standard;

internal static class AuthenticationConstant
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Copyright (c) MASA Stack All rights reserved.
// Copyright (c) MASA Stack All rights reserved.
// Licensed under the MIT License. See LICENSE.txt in the project root for license information.

namespace Masa.Contrib.Service.Caller.Authentication.BlazorServer;
namespace Masa.Contrib.Service.Caller.Authentication.Standard;

[System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
public class TokenProvider
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@
// Licensed under the MIT License. See LICENSE.txt in the project root for license information.

global using Masa.BuildingBlocks.Service.Caller;
global using Masa.Contrib.Service.Caller.Authentication;
global using Masa.Contrib.Service.Caller.Authentication.BlazorServer;
global using Masa.Contrib.Service.Caller.Authentication.Standard;
global using Microsoft.Extensions.DependencyInjection;
global using Microsoft.Extensions.DependencyInjection.Extensions;
global using System.Net.Http.Headers;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Copyright (c) MASA Stack All rights reserved.
// Licensed under the MIT License. See LICENSE.txt in the project root for license information.

namespace Masa.Contrib.Service.Caller.Authentication.BlazorServer.Tests;
namespace Masa.Contrib.Service.Caller.Authentication.Standard.Tests;

[TestClass]
public class AuthenticationServiceTest
Expand All @@ -20,7 +20,7 @@ public async Task TestExecuteAsync()
};
await authenticationService.ExecuteAsync(httpRequestMessage);
Assert.IsNotNull(httpRequestMessage.Headers.Authorization);
Assert.AreEqual($"{AuthenticationConstant.DEFAULT_SCHEME} {tokenProvider.Authorization}",httpRequestMessage.Headers.Authorization.ToString());
Assert.AreEqual($"{AuthenticationConstant.DEFAULT_SCHEME} {tokenProvider.Authorization}", httpRequestMessage.Headers.Authorization.ToString());
}

[TestMethod]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\..\Masa.Contrib.Service.Caller.Authentication.BlazorServer\Masa.Contrib.Service.Caller.Authentication.BlazorServer.csproj" />
<ProjectReference Include="..\..\Masa.Contrib.Service.Caller.Authentication.Standard\Masa.Contrib.Service.Caller.Authentication.Standard.csproj" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Copyright (c) MASA Stack All rights reserved.
// Licensed under the MIT License. See LICENSE.txt in the project root for license information.

namespace Masa.Contrib.Service.Caller.Authentication.BlazorServer.Tests;
namespace Masa.Contrib.Service.Caller.Authentication.Standard.Tests;

[TestClass]
public class MasaCallerClientBuilderExtensionsTest
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="IdentityModel" Version="6.1.0-preview.1" />
<PackageReference Include="IdentityModel" Version="$(IdentityModelPackageVersion)" />
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="$(MicrosoftPackageVersion)" />
</ItemGroup>

Expand All @@ -19,6 +19,7 @@
<ProjectReference Include="..\..\..\Utils\Extensions\Masa.Utils.Extensions.DependencyInjection\Masa.Utils.Extensions.DependencyInjection.csproj" />
<ProjectReference Include="..\..\Caching\Distributed\Masa.Contrib.Caching.Distributed.StackExchangeRedis\Masa.Contrib.Caching.Distributed.StackExchangeRedis.csproj" />
<ProjectReference Include="..\..\Caching\Masa.Contrib.Caching.MultilevelCache\Masa.Contrib.Caching.MultilevelCache.csproj" />
<ProjectReference Include="..\..\Service\Caller\Authentication\Masa.Contrib.Service.Caller.Authentication.Standard\Masa.Contrib.Service.Caller.Authentication.Standard.csproj" />
<ProjectReference Include="..\..\Service\Caller\Masa.Contrib.Service.Caller.HttpClient\Masa.Contrib.Service.Caller.HttpClient.csproj" />
</ItemGroup>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ public static IServiceCollection AddAuthClient(this IServiceCollection services,
return services.AddAuthClient(callerOptionsBuilder =>
{
callerOptionsBuilder
.UseHttpClient(builder => builder.BaseAddress = authServiceBaseAddress);//Need to use the AuthenticationService provided by MasaStack
.UseHttpClient(builder => builder.BaseAddress = authServiceBaseAddress)
.UseAuthentication();
}, redisOptions);
}

Expand All @@ -48,7 +49,7 @@ public static IServiceCollection AddAuthClient(this IServiceCollection services,
var authClient = new AuthClient(caller, userContext, authClientMultilevelCacheProvider.GetMultilevelCacheClient());
return authClient;
});
services.AddSingleton<IThirdPartyIdpService>(serviceProvider =>
services.AddScoped<IThirdPartyIdpService>(serviceProvider =>
{
var callProvider = serviceProvider.GetRequiredService<ICallerFactory>().Create(DEFAULT_CLIENT_NAME);
var authClientMultilevelCacheProvider = serviceProvider.GetRequiredService<AuthClientMultilevelCacheProvider>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@ public JwtTokenValidator(
_logger = logger;
}

public async Task ValidateTokenAsync(TokenProvider tokenProvider)
public async Task<ClaimsPrincipal?> ValidateTokenAsync(TokenProvider tokenProvider)
{
var discoveryDocument = await _httpClient.GetDiscoveryDocumentAsync(_jwtTokenValidatorOptions.AuthorityEndpoint);
var discoveryDocument = await GetDiscoveryDocument();
var validationParameters = new TokenValidationParameters
{
ValidateLifetime = _jwtTokenValidatorOptions.ValidateLifetime,
Expand All @@ -37,44 +37,61 @@ public async Task ValidateTokenAsync(TokenProvider tokenProvider)
};
JwtSecurityTokenHandler handler = new();
handler.InboundClaimTypeMap.Clear();
ClaimsPrincipal? claimsPrincipal = null;
try
{
handler.ValidateToken(tokenProvider.AccessToken, validationParameters, out SecurityToken _);
claimsPrincipal = handler.ValidateToken(tokenProvider.AccessToken, validationParameters, out SecurityToken _);
}
catch (SecurityTokenExpiredException)
{
if (!string.IsNullOrEmpty(tokenProvider.RefreshToken))
var tokenResult = await RefreshTokenAsync(tokenProvider.RefreshToken);
if (tokenResult != null)
{
var tokenClient = new TokenClient(_httpClient, new TokenClientOptions
{
Address = discoveryDocument.TokenEndpoint,
ClientId = _clientRefreshTokenOptions.ClientId,
ClientSecret = _clientRefreshTokenOptions.ClientSecret
});
var tokenResult = await tokenClient.RequestRefreshTokenAsync(tokenProvider.RefreshToken).ConfigureAwait(false);
if (tokenResult.IsError)
{
_logger?.LogError("JwtTokenValidator failed, RefreshToken failed, Error Message: {Message}", tokenResult.Error);
throw new UserFriendlyException($"JwtTokenValidator failed, RefreshToken failed, Error Message: {tokenResult.Error}");
}
else
{
tokenProvider.AccessToken = tokenResult.AccessToken;
handler.ValidateToken(tokenProvider.AccessToken, validationParameters, out SecurityToken _);
return handler.ValidateToken(tokenProvider.AccessToken, validationParameters, out SecurityToken _);
}
}
else
{
_logger?.LogWarning(
"RefreshToken is null,please AllowOfflineAccess value(true) and RequestedScopes should contains offline_access");
throw new UserFriendlyException("JwtTokenValidator failed, RefreshToken is null");
}
}
catch (Exception e)
{
_logger?.LogError(e, "JwtTokenValidator failed");
throw new UserFriendlyException("JwtTokenValidator failed");
}
return claimsPrincipal;
}

public async Task<TokenResponse?> RefreshTokenAsync(string? refreshToken)
{
if (string.IsNullOrEmpty(refreshToken))
{
_logger?.LogWarning("RefreshToken is null,please AllowOfflineAccess value(true) and RequestedScopes should contains offline_access");
throw new ArgumentNullException(nameof(refreshToken));
}
if (string.IsNullOrEmpty(_clientRefreshTokenOptions.ClientId))
{
_logger?.LogWarning("ClientRefreshTokenOptions.ClientId is empty,refresh token no work");
return null;
}
var tokenEndpoint = (await GetDiscoveryDocument()).TokenEndpoint;
var tokenClient = new TokenClient(_httpClient, new TokenClientOptions
{
Address = tokenEndpoint,
ClientId = _clientRefreshTokenOptions.ClientId,
ClientSecret = _clientRefreshTokenOptions.ClientSecret
});
var tokenResult = await tokenClient.RequestRefreshTokenAsync(refreshToken).ConfigureAwait(false);
return tokenResult;
}

private async Task<DiscoveryDocumentResponse> GetDiscoveryDocument()
{
return await _httpClient.GetDiscoveryDocumentAsync(_jwtTokenValidatorOptions.AuthorityEndpoint);
}

private static List<SecurityKey> GetIssuerSigningKeys(DiscoveryDocumentResponse discoveryDocument)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,15 @@ namespace Masa.Contrib.StackSdks.Caller;

public static class ServiceCollectionExtensions
{
public static IServiceCollection AddStackCaller(
this IServiceCollection services,
Assembly assembly,
Action<JwtTokenValidatorOptions> jwtTokenValidatorOptions,
Action<ClientRefreshTokenOptions>? clientRefreshTokenOptions = null)
{
return AddStackCaller(services, assembly, (serviceProvider) => new TokenProvider(), jwtTokenValidatorOptions, clientRefreshTokenOptions);
}

public static IServiceCollection AddStackCaller(
this IServiceCollection services,
Assembly assembly,
Expand All @@ -16,7 +25,7 @@ public static IServiceCollection AddStackCaller(

services.Configure(jwtTokenValidatorOptions);
services.Configure(clientRefreshTokenOptions);
services.AddScoped((serviceProvider) => { return tokenProvider.Invoke(serviceProvider); });
services.TryAddScoped((serviceProvider) => { return tokenProvider.Invoke(serviceProvider); });
services.AddSingleton<JwtTokenValidator>();
services.AddAutoRegistrationCaller(assembly);
return services;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,12 @@
global using Masa.BuildingBlocks.Service.Caller;
global using Masa.Contrib.Service.Caller.HttpClient;
global using Microsoft.Extensions.DependencyInjection;
global using Microsoft.Extensions.DependencyInjection.Extensions;
global using Microsoft.Extensions.Logging;
global using Microsoft.Extensions.Options;
global using Microsoft.IdentityModel.Tokens;
global using System.IdentityModel.Tokens.Jwt;
global using System.Net.Http.Headers;
global using System.Reflection;
global using System.Security.Claims;
global using System.Security.Cryptography;
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

<ItemGroup>
<ProjectReference Include="..\..\..\BuildingBlocks\StackSdks\Masa.BuildingBlocks.StackSdks.Mc\Masa.BuildingBlocks.StackSdks.Mc.csproj" />
<ProjectReference Include="..\..\Service\Caller\Authentication\Masa.Contrib.Service.Caller.Authentication.Standard\Masa.Contrib.Service.Caller.Authentication.Standard.csproj" />
<ProjectReference Include="..\..\Service\Caller\Masa.Contrib.Service.Caller.HttpClient\Masa.Contrib.Service.Caller.HttpClient.csproj" />
</ItemGroup>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ public static IServiceCollection AddMcClient(this IServiceCollection services, s
callerOptions.UseHttpClient(builder =>
{
builder.Configure = opt => opt.BaseAddress = new Uri(mcServiceBaseAddress);
}); //Need to use the AuthenticationService provided by MasaStack
}).UseAuthentication();
});
}

Expand All @@ -30,7 +30,7 @@ public static IServiceCollection AddMcClient(this IServiceCollection services, F
.UseHttpClient(builder =>
{
builder.BaseAddress = mcServiceBaseAddressFunc.Invoke();
}); //Need to use the AuthenticationService provided by MasaStack
}).UseAuthentication();
});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
<ItemGroup>
<ProjectReference Include="..\..\..\BuildingBlocks\StackSdks\Masa.BuildingBlocks.StackSdks.Pm\Masa.BuildingBlocks.StackSdks.Pm.csproj" />
<ProjectReference Include="..\..\..\Utils\Configuration\Masa.Utils.Configuration.Json\Masa.Utils.Configuration.Json.csproj" />
<ProjectReference Include="..\..\Service\Caller\Authentication\Masa.Contrib.Service.Caller.Authentication.Standard\Masa.Contrib.Service.Caller.Authentication.Standard.csproj" />
<ProjectReference Include="..\..\Service\Caller\Masa.Contrib.Service.Caller.HttpClient\Masa.Contrib.Service.Caller.HttpClient.csproj" />
</ItemGroup>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ public static IServiceCollection AddPmClient(this IServiceCollection services, s
callerOptions.UseHttpClient(builder =>
{
builder.BaseAddress = pmServiceBaseAddress;
});
}).UseAuthentication();
});
}

Expand All @@ -29,7 +29,7 @@ public static IServiceCollection AddPmClient(this IServiceCollection services, F
callerOptions.UseHttpClient(builder =>
{
builder.BaseAddress = pmServiceBaseAddressFunc.Invoke();
}); //Need to use the AuthenticationService provided by MasaStack
}).UseAuthentication();
});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
<ItemGroup>
<ProjectReference Include="..\..\..\BuildingBlocks\Authentication\Masa.BuildingBlocks.Authentication.Identity\Masa.BuildingBlocks.Authentication.Identity.csproj" />
<ProjectReference Include="..\..\..\BuildingBlocks\StackSdks\Masa.BuildingBlocks.StackSdks.Scheduler\Masa.BuildingBlocks.StackSdks.Scheduler.csproj" />
<ProjectReference Include="..\..\Service\Caller\Authentication\Masa.Contrib.Service.Caller.Authentication.AspNetCore\Masa.Contrib.Service.Caller.Authentication.AspNetCore.csproj" />
<ProjectReference Include="..\..\Service\Caller\Authentication\Masa.Contrib.Service.Caller.Authentication.Standard\Masa.Contrib.Service.Caller.Authentication.Standard.csproj" />
<ProjectReference Include="..\..\Service\Caller\Masa.Contrib.Service.Caller.HttpClient\Masa.Contrib.Service.Caller.HttpClient.csproj" />
</ItemGroup>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public static IServiceCollection AddSchedulerClient(this IServiceCollection serv
.UseHttpClient(builder =>
{
builder.Configure = opt => opt.BaseAddress = new Uri(schedulerServiceBaseAddress);
}); //Need to use the AuthenticationService provided by MasaStack
}).UseAuthentication();
});
}

Expand Down
Loading

0 comments on commit c300f24

Please sign in to comment.