Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

⚡ refactor: Cache Client Credentials Token #595

Merged
merged 5 commits into from
Sep 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions Masa.Mc.sln
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Masa.Mc.Infrastructure.Weix
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Masa.Mc.Infrastructure.OptionsResolve", "src\Infrastructure\Masa.Mc.Infrastructure.OptionsResolve\Masa.Mc.Infrastructure.OptionsResolve.csproj", "{7F815157-EB5A-4DF5-9B10-D9D751CB6FC9}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Masa.Mc.Infrastructure.Cache", "src\Infrastructure\Masa.Mc.Infrastructure.Cache\Masa.Mc.Infrastructure.Cache.csproj", "{01FB3AEA-B756-4F53-8CD1-3C77D072E8E6}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -237,6 +239,14 @@ Global
{7F815157-EB5A-4DF5-9B10-D9D751CB6FC9}.Release|Any CPU.Build.0 = Release|Any CPU
{7F815157-EB5A-4DF5-9B10-D9D751CB6FC9}.Release|x86.ActiveCfg = Release|Any CPU
{7F815157-EB5A-4DF5-9B10-D9D751CB6FC9}.Release|x86.Build.0 = Release|Any CPU
{01FB3AEA-B756-4F53-8CD1-3C77D072E8E6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{01FB3AEA-B756-4F53-8CD1-3C77D072E8E6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{01FB3AEA-B756-4F53-8CD1-3C77D072E8E6}.Debug|x86.ActiveCfg = Debug|Any CPU
{01FB3AEA-B756-4F53-8CD1-3C77D072E8E6}.Debug|x86.Build.0 = Debug|Any CPU
{01FB3AEA-B756-4F53-8CD1-3C77D072E8E6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{01FB3AEA-B756-4F53-8CD1-3C77D072E8E6}.Release|Any CPU.Build.0 = Release|Any CPU
{01FB3AEA-B756-4F53-8CD1-3C77D072E8E6}.Release|x86.ActiveCfg = Release|Any CPU
{01FB3AEA-B756-4F53-8CD1-3C77D072E8E6}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down Expand Up @@ -267,6 +277,7 @@ Global
{7F2708C3-F1EE-4BFD-9321-F8D90390BF3C} = {4660010F-BB9B-4C8E-B4F7-34AF77080EA0}
{58E1DBB5-409C-4DF7-BDCA-A36715E0BB86} = {4660010F-BB9B-4C8E-B4F7-34AF77080EA0}
{7F815157-EB5A-4DF5-9B10-D9D751CB6FC9} = {4660010F-BB9B-4C8E-B4F7-34AF77080EA0}
{01FB3AEA-B756-4F53-8CD1-3C77D072E8E6} = {4660010F-BB9B-4C8E-B4F7-34AF77080EA0}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {B83BA2BA-19E5-41FB-A92A-16A03DA229E4}
Expand Down
2 changes: 0 additions & 2 deletions src/ApiGateways/Caller/Masa.Mc.ApiGateways.Caller/McCaller.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@ namespace Masa.Mc.ApiGateways.Caller;

public class McCaller : StackHttpClientCaller
{
private const string DEFAULT_SCHEME = "Bearer";

#region Field
ChannelService? _channelService;
MessageTemplateService? _messageTemplateService;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,6 @@ public static class BusinessConsts
public const string IS_APNS_PRODUCTION = "IsApnsProduction";
public const string APP_PUSH_MSG_ID = "MsgId";
public const string MESSAGE_TYPE = "MessageType";
public const string COMMON_SCOPE = "MasaStack";
}

6 changes: 6 additions & 0 deletions src/Contracts/Masa.Mc.Contracts.Admin/Consts/CacheKeys.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,10 @@ public class CacheKeys
{
public const string MESSAGE_CURSOR_CHECK_COUNT = nameof(MESSAGE_CURSOR_CHECK_COUNT);
public const string GET_NOTICE_LIST = nameof(GET_NOTICE_LIST);
public const string CLIENT_CREDENTIALS_TOKEN = "client_credentials_token:";

public static string ClientCredentialsTokenKey(string clientId)
{
return $"{CLIENT_CREDENTIALS_TOKEN}{clientId}";
}
}

This file was deleted.

73 changes: 73 additions & 0 deletions src/Infrastructure/Masa.Mc.Infrastructure.Cache/CacheContext.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
namespace Masa.Mc.Infrastructure.Cache;

internal class CacheContext : ICacheContext
{
readonly IMultilevelCacheClient _multilevelCache;

readonly MultilevelCacheGlobalOptions _cacheOption;

public CacheContext(
IMultilevelCacheClient multilevelCache,
IOptions<MultilevelCacheGlobalOptions> cacheOption)
{
_multilevelCache = multilevelCache;
_cacheOption = cacheOption.Value;
}


public async Task SetAsync<T>(string key, T item, CacheEntryOptions? cacheEntryOptions)
{
await _multilevelCache.SetAsync(key, item, cacheEntryOptions ?? _cacheOption.CacheEntryOptions);
}


public async Task<T?> GetAsync<T>(string key)
{
return await _multilevelCache.GetAsync<T>(key);
}

public async Task Remove<T>(string key)
{
await _multilevelCache.RemoveAsync<T>(key);
}

public async Task<T> GetOrSetAsync<T>(string key, Func<Task<T>> setter, CacheEntryOptions? cacheEntryOptions)
{
cacheEntryOptions ??= _cacheOption.CacheEntryOptions!;

var value = await _multilevelCache.GetAsync<T>(key);

if (value != null)
return value;

value = await setter();

await _multilevelCache.SetAsync(key, value, new CombinedCacheEntryOptions
{
MemoryCacheEntryOptions = cacheEntryOptions,
DistributedCacheEntryOptions = cacheEntryOptions
});

return value;
}

public async Task<T> GetOrSetAsync<T>(string key, Func<Task<(T, CacheEntryOptions cacheEntryOptions)>> setter)
{
var value = await _multilevelCache.GetAsync<T>(key);

if (value != null)
return value;

var setterResult = await setter();
value = setterResult.Item1;
var cacheEntryOptions = setterResult.Item2;

await _multilevelCache.SetAsync(key, value, new CombinedCacheEntryOptions
{
MemoryCacheEntryOptions = cacheEntryOptions,
DistributedCacheEntryOptions = cacheEntryOptions
});

return value;
}
}
14 changes: 14 additions & 0 deletions src/Infrastructure/Masa.Mc.Infrastructure.Cache/ICacheContext.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
namespace Masa.Mc.Infrastructure.Cache;

public interface ICacheContext
{
Task SetAsync<T>(string key, T item, CacheEntryOptions? cacheEntryOptions = default);

Task<T?> GetAsync<T>(string key);

Task<T> GetOrSetAsync<T>(string key, Func<Task<T>> setter, CacheEntryOptions? cacheEntryOptions = default);

Task<T> GetOrSetAsync<T>(string key, Func<Task<(T, CacheEntryOptions cacheEntryOptions)>> setter);

Task Remove<T>(string key);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Masa.Contrib.Caching.MultilevelCache" Version="$(MasaFrameworkPackageVersion)" />
<PackageReference Include="Masa.Contrib.Caching.Distributed.StackExchangeRedis" Version="$(MasaFrameworkPackageVersion)" />
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="6.0.0" />
</ItemGroup>
</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
namespace Masa.Mc.Infrastructure.Cache;

public static class ServiceCollectionExtensions
{
public static IServiceCollection AddCache(this IServiceCollection services)
{
services.AddMultilevelCache(options => options.UseStackExchangeRedisCache());
services.AddSingleton<ICacheContext, CacheContext>();
return services;
}
}
8 changes: 8 additions & 0 deletions src/Infrastructure/Masa.Mc.Infrastructure.Cache/_Imports.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
global using Microsoft.Extensions.DependencyInjection;
global using Microsoft.Extensions.DependencyInjection.Extensions;
global using Microsoft.Extensions.Configuration;
global using Masa.BuildingBlocks.Caching;
global using Masa.Contrib.Caching.Distributed.StackExchangeRedis;
global using Masa.Contrib.Caching.MultilevelCache;
global using Microsoft.Extensions.Options;
global using Masa.Mc.Infrastructure.Cache;
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
// Copyright (c) MASA Stack All rights reserved.
// Licensed under the Apache License. See LICENSE.txt in the project root for license information.

namespace Masa.Mc.Service.Admin.Infrastructure.Authentication;

public class TokenGenerater : ITokenGenerater
{
private readonly IHttpContextAccessor _httpContextAccessor;
private readonly HttpClient _httpClient;
private readonly IMasaStackConfig _masaStackConfig;
private const string SCHEME = "Bearer ";
private readonly ICacheContext _cacheContext;

public TokenGenerater(IHttpContextAccessor httpContextAccessor, HttpClient httpClient, IMasaStackConfig masaStackConfig, ICacheContext cacheContext)
{
_httpContextAccessor = httpContextAccessor;
_httpClient = httpClient;
_masaStackConfig = masaStackConfig;
_cacheContext = cacheContext;
}

public TokenProvider Generater()
{
StringValues authenticationHeaderValue;

if (_httpContextAccessor.HttpContext?.Request.Headers.TryGetValue("Authorization", out authenticationHeaderValue) == true)
{
var accessToken = authenticationHeaderValue.ToString();

if (!string.IsNullOrEmpty(accessToken) && accessToken.StartsWith(SCHEME, StringComparison.OrdinalIgnoreCase))
{
accessToken = accessToken.Substring(SCHEME.Length).Trim();
}

return new TokenProvider { AccessToken = accessToken };
}

if (_httpContextAccessor.HttpContext == null)
{
var accessToken = GetClientCredentialsTokenAsync().Result;
return new TokenProvider { AccessToken = accessToken };
}

return new TokenProvider();
}

private async Task<string> GetClientCredentialsTokenAsync()
{
var accessToken = await _cacheContext.GetOrSetAsync(CacheKeys.ClientCredentialsTokenKey(_masaStackConfig.GetWebId(MasaStackProject.MC)),
async () =>
{
var request = new ClientCredentialsTokenRequest
{
Address = _masaStackConfig.GetSsoDomain() + "/connect/token",
GrantType = BuildingBlocks.Authentication.OpenIdConnect.Models.Constans.GrantType.CLIENT_CREDENTIALS,
ClientId = _masaStackConfig.GetWebId(MasaStackProject.MC),
Scope = BusinessConsts.COMMON_SCOPE
};
var tokenResponse = await _httpClient.RequestClientCredentialsTokenAsync(request);

var cacheEntryOptions = new CacheEntryOptions
{
AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(tokenResponse.ExpiresIn - 60)
};
return (tokenResponse.AccessToken, cacheEntryOptions);
}
);

return accessToken;
}
}
1 change: 1 addition & 0 deletions src/Services/Masa.Mc.Service/Masa.Mc.Service.Admin.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@
<ItemGroup>
<ProjectReference Include="..\..\Contracts\Masa.Mc.Contracts.Admin\Masa.Mc.Contracts.Admin.csproj" />
<ProjectReference Include="..\..\Infrastructure\Masa.Mc.Infrastructure.AppNotification\Masa.Mc.Infrastructure.AppNotification.csproj" />
<ProjectReference Include="..\..\Infrastructure\Masa.Mc.Infrastructure.Cache\Masa.Mc.Infrastructure.Cache.csproj" />
<ProjectReference Include="..\..\Infrastructure\Masa.Mc.Infrastructure.Common\Masa.Mc.Infrastructure.Common.csproj" />
<ProjectReference Include="..\..\Infrastructure\Masa.Mc.Infrastructure.Ddd.Application.Contracts\Masa.Mc.Infrastructure.Ddd.Application.Contracts.csproj" />
<ProjectReference Include="..\..\Infrastructure\Masa.Mc.Infrastructure.Email\Masa.Mc.Infrastructure.Email.csproj" />
Expand Down
2 changes: 1 addition & 1 deletion src/Services/Masa.Mc.Service/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -96,11 +96,11 @@
};
var configuration = builder.Services.GetMasaConfiguration().ConfigurationApi.GetDefault();
builder.Services.AddScoped<ITokenGenerater, TokenGenerater>();
builder.Services.AddCache();
builder.Services.AddAuthClient(masaStackConfig.GetAuthServiceDomain(), redisOptions);
builder.Services.AddMcClient(masaStackConfig.GetMcServiceDomain());
builder.Services.AddPmClient(masaStackConfig.GetPmServiceDomain());
builder.Services.AddSchedulerClient(masaStackConfig.GetSchedulerServiceDomain());
builder.Services.AddMultilevelCache(options => options.UseStackExchangeRedisCache());
builder.Services.AddAliyunSms();
builder.Services.AddMailKit();
builder.Services.AddAppNotification();
Expand Down
6 changes: 4 additions & 2 deletions src/Services/Masa.Mc.Service/_Imports.cs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
global using Masa.Contrib.Ddd.Domain.Repository.EFCore;
global using Masa.Contrib.Dispatcher.Events;
global using Masa.Contrib.Dispatcher.IntegrationEvents.EventLogs.EFCore;
global using Masa.Contrib.StackSdks.Caller;
global using Masa.Contrib.StackSdks.Config;
global using Masa.Contrib.StackSdks.Isolation;
global using Masa.Contrib.StackSdks.Mc.Infrastructure.Extensions;
Expand Down Expand Up @@ -91,6 +92,7 @@
global using Masa.Mc.Contracts.Admin.Scheduler;
global using Masa.Mc.Infrastructure.AppNotification;
global using Masa.Mc.Infrastructure.AppNotification.Infrastructure.OptionsResolve;
global using Masa.Mc.Infrastructure.Cache;
global using Masa.Mc.Infrastructure.Common.Helper;
global using Masa.Mc.Infrastructure.Common.Utils;
global using Masa.Mc.Infrastructure.Ddd.Application.Contracts.Dtos;
Expand Down Expand Up @@ -158,6 +160,7 @@
global using Masa.Mc.Service.Admin.Domain.WebsiteMessages.Events;
global using Masa.Mc.Service.Admin.Domain.WebsiteMessages.Repositories;
global using Masa.Mc.Service.Admin.Domain.WebsiteMessages.Services;
global using Masa.Mc.Service.Admin.Infrastructure.Authentication;
global using Masa.Mc.Service.Admin.Infrastructure.ChannelUserFinder.Provider.Auth;
global using Masa.Mc.Service.Admin.Infrastructure.Constants;
global using Masa.Mc.Service.Admin.Infrastructure.EntityFrameworkCore;
Expand Down Expand Up @@ -187,5 +190,4 @@
global using static AlibabaCloud.SDK.Dysmsapi20170525.Models.QuerySmsTemplateListResponseBody;
global using ICsvExporter = Masa.Mc.Infrastructure.ExporterAndImporter.Csv.ICsvExporter;
global using ICsvImporter = Masa.Mc.Infrastructure.ExporterAndImporter.Csv.ICsvImporter;
global using IdentityModel.Client;
global using Masa.Contrib.StackSdks.Caller;
global using IdentityModel.Client;
1 change: 0 additions & 1 deletion src/Web/Masa.Mc.Web.Admin.Server/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@
mcBaseAddress = masaStackConfig.GetMcServiceDomain();
}

builder.Services.AddScoped<ITokenGenerater, TokenGenerater>();
await builder.Services.AddMasaStackComponentsAsync(MasaStackProject.MC, "wwwroot/i18n", authBaseAddress);

builder.Services.AddHttpContextAccessor();
Expand Down