Skip to content

Commit

Permalink
feature(oidc):add Oidc.EntityFramework、Oidc.Cache.Storage (#78)
Browse files Browse the repository at this point in the history
* add oidc project

* feat(oidc):oidc

* feat(oidc):oidc

* feat(oidc):oidc

* feat(oidc):oidc

* feat(oidc):oidc

* feat(oidc):oidc

* feat(oidc):oidc

* feat(oidc):oidc

* feat:add redis cache options

* feat(oidc):oidc

* feat(oidc):oidc

* feat(oidc):oidc

* feat:update cache

* feat(oidc):oidc

* feat(oidc)Loidc

* feat(oidc):oidc

* feat(oidc):oidc

* refactor:formatting code

* feat(oidc):remove AddAllAsync,add ResetAsync

* refactor(code):refactor code

* refactor:refactor code

* refactor:refactor code

* refactor:refactor code

* refactor(code):refactor code

* merge:merges the latest code in the main branch

Co-authored-by: Mayue <[email protected]>
  • Loading branch information
wuweilaiya and Mayue authored Jun 21, 2022
1 parent 5bcedfb commit e20bc7d
Show file tree
Hide file tree
Showing 53 changed files with 1,822 additions and 48 deletions.
167 changes: 120 additions & 47 deletions Masa.Contrib.sln

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<WarningsAsErrors>
$(WarningsAsErrors);CS8600;CS8601;CS8602;CS8603;CS8604;CS8609;CS8610;CS8614;CS8616;CS8618;CS8619;CS8620;CS8622;CS8625
</WarningsAsErrors>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Masa.Utils.Caching.DistributedMemory" Version="$(MasaUtilsPackageVersion)" />
<PackageReference Include="Masa.Utils.Caching.Redis" Version="$(MasaUtilsPackageVersion)" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\..\BuildingBlocks\MASA.BuildingBlocks\src\Authentication\Masa.BuildingBlocks.Authentication.Oidc.Storage\Masa.BuildingBlocks.Authentication.Oidc.Storage.csproj" />
<ProjectReference Include="..\Masa.Contrib.Authentication.Oidc.Cache\Masa.Contrib.Authentication.Oidc.Cache.csproj" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// 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.Authentication.Oidc.Cache.Storage;

public static class ServiceCollectionExtensions
{
public static IServiceCollection AddOidcCacheStorage(this IServiceCollection services, RedisConfigurationOptions options)
{
services.AddOidcCache(options);
services.AddSingleton<IClientStore, ClientStore>();
services.AddSingleton<IResourceStore, ResourceStore>();
services.AddSingleton<IPersistedGrantStore, PersistedGrantStore>();
services.AddSingleton<IDeviceFlowStore, DeviceFlowStore>();

return services;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// 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.Authentication.Oidc.Cache.Storage.Stores;

public class ClientStore : IClientStore
{
IClientCache _clientCache;

public ClientStore(IClientCache clientCache)
{
_clientCache = clientCache;
}

public async Task<ClientModel?> FindClientByIdAsync(string clientId)
{
ArgumentNullException.ThrowIfNull(clientId);

var client = await _clientCache.GetAsync(clientId);
return client;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// 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.Authentication.Oidc.Cache.Storage.Stores;

public class DeviceFlowStore : IDeviceFlowStore
{
public Task<DeviceCodeModel> FindByDeviceCodeAsync(string deviceCode)
{
throw new NotImplementedException();
}

public Task<DeviceCodeModel> FindByUserCodeAsync(string userCode)
{
throw new NotImplementedException();
}

public Task RemoveByDeviceCodeAsync(string deviceCode)
{
throw new NotImplementedException();
}

public Task StoreDeviceAuthorizationAsync(string deviceCode, string userCode, DeviceCodeModel data)
{
throw new NotImplementedException();
}

public Task UpdateByUserCodeAsync(string userCode, DeviceCodeModel data)
{
throw new NotImplementedException();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// 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.Authentication.Oidc.Cache.Storage.Stores;

public class PersistedGrantStore : IPersistedGrantStore
{
public Task<IEnumerable<PersistedGrantModel>> GetAllAsync(PersistedGrantFilter filter)
{
throw new NotImplementedException();
}

public Task<PersistedGrantModel> GetAsync(string key)
{
throw new NotImplementedException();
}

public Task RemoveAllAsync(PersistedGrantFilter filter)
{
throw new NotImplementedException();
}

public Task RemoveAsync(string key)
{
throw new NotImplementedException();
}

public Task StoreAsync(PersistedGrantModel grant)
{
throw new NotImplementedException();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// 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.Authentication.Oidc.Cache.Storage.Stores;

public class ResourceStore : IResourceStore
{
IIdentityResourceCache _identityResourceCache;
IApiResourceCache _apiResourceCache;
IApiScopeCache _apiScopeCache;

public ResourceStore(IIdentityResourceCache identityResourceCache, IApiResourceCache apiResourceCache, IApiScopeCache apiScopeCache)
{
_identityResourceCache = identityResourceCache;
_apiResourceCache = apiResourceCache;
_apiScopeCache = apiScopeCache;
}

public async Task<IEnumerable<ApiResourceModel>> FindApiResourcesByNameAsync(IEnumerable<string> apiResourceNames)
{
ArgumentNullException.ThrowIfNull(apiResourceNames);

return await _apiResourceCache.GetListAsync(apiResourceNames);
}

public async Task<IEnumerable<ApiResourceModel>> FindApiResourcesByScopeNameAsync(IEnumerable<string> scopeNames)
{
ArgumentNullException.ThrowIfNull(scopeNames);

var apiResources = await _apiResourceCache.GetListAsync();
return apiResources.Where(apiResource => apiResource.Scopes?.Any(scope => scopeNames.Contains(scope)) is true);
}

public async Task<IEnumerable<ApiScopeModel>> FindApiScopesByNameAsync(IEnumerable<string> scopeNames)
{
ArgumentNullException.ThrowIfNull(scopeNames);

var apiScopes = await _apiScopeCache.GetListAsync(scopeNames);
return apiScopes;
}

public async Task<IEnumerable<IdentityResourceModel>> FindIdentityResourcesByScopeNameAsync(IEnumerable<string> scopeNames)
{
ArgumentNullException.ThrowIfNull(scopeNames);

var identityResources = await _identityResourceCache.GetListAsync(scopeNames);
return identityResources;
}

public async Task<ResourcesModel> GetAllResourcesAsync()
{
var identityResources = await _identityResourceCache.GetListAsync();
var apiScopes = await _apiScopeCache.GetListAsync();
var apiResources = await _apiResourceCache.GetListAsync();
var resources = new ResourcesModel(identityResources, apiResources, apiScopes);
return resources;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// Copyright (c) MASA Stack All rights reserved.
// Licensed under the MIT License. See LICENSE.txt in the project root for license information.

global using Masa.BuildingBlocks.Authentication.Oidc.Cache.Caches;
global using Masa.BuildingBlocks.Authentication.Oidc.Models.Models;
global using Masa.BuildingBlocks.Authentication.Oidc.Storage.Stores;
global using Masa.Contrib.Authentication.Oidc.Cache.Storage.Stores;
global using Microsoft.Extensions.DependencyInjection;
global using Masa.Utils.Caching.Redis.Models;
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
// 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.Authentication.Oidc.Cache.Caches;

public class ApiResourceCache : IApiResourceCache
{
IMemoryCacheClient _memoryCacheClient;

public ApiResourceCache(IMemoryCacheClient memoryCacheClient)
{
_memoryCacheClient = memoryCacheClient;
}

public async Task<List<ApiResourceModel>> GetListAsync(IEnumerable<string> names)
{
var keys = names.Select(name => $"{CacheKeyConstants.API_RESOURCE_KEY}_{name}");
var apiResources = await _memoryCacheClient.GetListAsync<ApiResourceModel>(keys.ToArray());
return apiResources.Where(i => i is not null).ToList()!;
}

public async Task<List<ApiResourceModel>> GetListAsync()
{
var apiResources = await _memoryCacheClient.GetAsync<List<ApiResourceModel>>(CacheKeyConstants.API_RESOURCE_KEY) ?? new();
return apiResources;
}

public async Task SetAsync(ApiResource apiResource)
{
var model = apiResource.ToModel();
string key = $"{CacheKeyConstants.API_RESOURCE_KEY}_{apiResource.Name}";
await _memoryCacheClient.SetAsync(key, model);
// update list cache
var list = await GetListAsync();
list.Set(model, item => item.Name);
await UpdateListAsync(list);
}

public async Task SetRangeAsync(IEnumerable<ApiResource> apiResources)
{
var models = apiResources.Select(apiScope => apiScope.ToModel());
var map = models.ToDictionary(model => $"{CacheKeyConstants.API_RESOURCE_KEY}_{model.Name}", model => model);
await _memoryCacheClient.SetListAsync(map);
// update list cache
var list = await GetListAsync();
list.SetRange(models, item => item.Name);
await UpdateListAsync(list);
}

public async Task RemoveAsync(ApiResource apiResource)
{
string key = $"{CacheKeyConstants.API_RESOURCE_KEY}_{apiResource.Name}";
await _memoryCacheClient.RemoveAsync<ApiResourceModel>(key);
// update list cache
var list = await GetListAsync();
list.Remove(item => item.Name == apiResource.Name);
await UpdateListAsync(list);
}

public async Task ResetAsync(IEnumerable<ApiResource> apiResources)
{
var models = apiResources.Select(apiScope => apiScope.ToModel());
await UpdateListAsync(models);
var map = models.ToDictionary(model => $"{CacheKeyConstants.API_RESOURCE_KEY}_{model.Name}", model => model);
await _memoryCacheClient.SetListAsync(map);
}

private async Task UpdateListAsync(IEnumerable<ApiResourceModel> models)
{
await _memoryCacheClient.SetAsync(CacheKeyConstants.API_RESOURCE_KEY, models);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
// 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.Authentication.Oidc.Cache.Caches;

public class ApiScopeCache : IApiScopeCache
{
IMemoryCacheClient _memoryCacheClient;

public ApiScopeCache(IMemoryCacheClient memoryCacheClient)
{
_memoryCacheClient = memoryCacheClient;
}

public async Task<List<ApiScopeModel>> GetListAsync(IEnumerable<string> names)
{
var keys = names.Select(name => $"{CacheKeyConstants.API_SCOPE_KEY}_{name}");
var apiScopes = await _memoryCacheClient.GetListAsync<ApiScopeModel>(keys.ToArray());
return apiScopes.Where(i => i is not null).ToList()!;
}

public async Task<List<ApiScopeModel>> GetListAsync()
{
var ApiScopes = await _memoryCacheClient.GetAsync<List<ApiScopeModel>>(CacheKeyConstants.API_SCOPE_KEY) ?? new();
return ApiScopes;
}

public async Task SetAsync(ApiScope apiScope)
{
string key = $"{CacheKeyConstants.API_SCOPE_KEY}_{apiScope.Name}";
var model = apiScope.ToModel();
await _memoryCacheClient.SetAsync(key, model);
// update list cache
var list = await GetListAsync();
list.Set(model, item => item.Name);
await UpdateListAsync(list);
}

public async Task SetRangeAsync(IEnumerable<ApiScope> apiScopes)
{
var models = apiScopes.Select(apiScope => apiScope.ToModel());
var data = models.ToDictionary(model => $"{CacheKeyConstants.API_SCOPE_KEY}_{model.Name}", model => model);
await _memoryCacheClient.SetListAsync(data);
// update list cache
var list = await GetListAsync();
list.SetRange(models, item => item.Name);
await UpdateListAsync(list);
}

public async Task RemoveAsync(ApiScope apiScope)
{
string key = $"{CacheKeyConstants.API_SCOPE_KEY}_{apiScope.Name}";
await _memoryCacheClient.RemoveAsync<ApiScopeModel>(key);
// update list cache
var list = await GetListAsync();
list.Remove(item => item.Name == apiScope.Name);
await UpdateListAsync(list);
}

public async Task ResetAsync(IEnumerable<ApiScope> apiScopes)
{
var models = apiScopes.Select(apiScope => apiScope.ToModel());
await UpdateListAsync(models);
var map = models.ToDictionary(model => $"{CacheKeyConstants.API_SCOPE_KEY}_{model.Name}", model => model);
await _memoryCacheClient.SetListAsync(map);
}

private async Task UpdateListAsync(IEnumerable<ApiScopeModel> models)
{
await _memoryCacheClient.SetAsync(CacheKeyConstants.API_SCOPE_KEY, models);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// 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.Authentication.Oidc.Cache.Caches;

public class ClientCache : IClientCache
{
IMemoryCacheClient _memoryCacheClient;

public ClientCache(IMemoryCacheClient memoryCacheClient)
{
_memoryCacheClient = memoryCacheClient;
}

public async Task<ClientModel?> GetAsync(string clientId)
{
string key = $"{CacheKeyConstants.CLIENT_KEY}_{clientId}";
return await _memoryCacheClient.GetAsync<ClientModel>(key);
}

public async Task SetAsync(Client client)
{
string key = $"{CacheKeyConstants.CLIENT_KEY}_{client.ClientId}";
await _memoryCacheClient.SetAsync(key, client.ToModel());
}

public async Task RemoveAsync(Client client)
{
string key = $"{CacheKeyConstants.CLIENT_KEY}_{client.ClientId}";
await _memoryCacheClient.RemoveAsync<ClientModel>(key);
}

public async Task SetRangeAsync(IEnumerable<Client> clients)
{
var data = clients.ToDictionary(client => $"{CacheKeyConstants.CLIENT_KEY}_{client.ClientId}", client => client.ToModel());
await _memoryCacheClient.SetListAsync(data);
}
}
Loading

0 comments on commit e20bc7d

Please sign in to comment.