网站首页 网站源码
using System.Collections.Immutable;
using System.Globalization;
using System.Runtime.CompilerServices;
using System.Text.Json;
using Dpz.Core.EnumLibrary;
using Dpz.Core.MongodbAccess;
using Dpz.Core.Public.Entity.Auth;
using Microsoft.Extensions.Logging;
using Microsoft.IdentityModel.Tokens;
using MongoDB.Bson;
using MongoDB.Driver;
using MongoDB.Driver.Linq;
using OpenIddict.Abstractions;
namespace Dpz.Core.Auth.Service;
public sealed class DpzApplicationStore(
IRepository<DpzApplication> repository,
ILogger<DpzApplicationStore> logger
) : IOpenIddictApplicationStore<DpzApplication>
{
public async ValueTask<long> CountAsync(CancellationToken cancellationToken)
{
logger.LogInformation("Counting applications");
return await repository.Collection.CountDocumentsAsync(
FilterDefinition<DpzApplication>.Empty,
cancellationToken: cancellationToken
);
}
public async ValueTask<long> CountAsync<TResult>(
Func<IQueryable<DpzApplication>, IQueryable<TResult>> query,
CancellationToken cancellationToken
)
{
logger.LogInformation("Counting applications with custom query");
return await query(repository.MongodbQueryable)
.LongCountAsync(cancellationToken: cancellationToken);
}
public async ValueTask CreateAsync(
DpzApplication application,
CancellationToken cancellationToken
)
{
logger.LogInformation(
"Creating application {ClientId} ({Id})",
application.ClientId,
application.Id
);
await repository.InsertAsync(application, cancellationToken);
}
public async ValueTask DeleteAsync(
DpzApplication application,
CancellationToken cancellationToken
)
{
await repository.DeleteAsync(application.Id, cancellationToken);
}
public async ValueTask<DpzApplication?> FindByIdAsync(
string identifier,
CancellationToken cancellationToken
)
{
if (ObjectId.TryParse(identifier, out var oid))
{
return await repository.FindAsync(oid, cancellationToken);
}
return null;
}
public async ValueTask<DpzApplication?> FindByClientIdAsync(
string identifier,
CancellationToken cancellationToken
)
{
var application = await repository
.SearchFor(x => x.ClientId == identifier)
.FirstOrDefaultAsync(cancellationToken);
return application;
}
public IAsyncEnumerable<DpzApplication> FindByPostLogoutRedirectUriAsync(
string uri,
CancellationToken cancellationToken
)
{
var filter = Builders<DpzApplication>.Filter.Eq(x => x.PostLogoutRedirectUri, uri);
return repository.SearchForAsync(filter, cancellationToken);
}
public IAsyncEnumerable<DpzApplication> FindByRedirectUriAsync(
string uri,
CancellationToken cancellationToken
)
{
var filter = Builders<DpzApplication>.Filter.Eq(x => x.RedirectUris, uri);
return repository.SearchForAsync(filter, cancellationToken);
}
public async ValueTask<string?> GetApplicationTypeAsync(
DpzApplication application,
CancellationToken cancellationToken
)
{
if (!string.IsNullOrWhiteSpace(application.ApplicationType))
{
return application.ApplicationType;
}
if (application.Id != default || application.Id != ObjectId.Empty)
{
return (
await FindByIdAsync(application.Id.ToString(), cancellationToken)
)?.ApplicationType;
}
if (!string.IsNullOrWhiteSpace(application.ClientId))
{
return (
await FindByClientIdAsync(application.ClientId, cancellationToken)
)?.ApplicationType;
}
return null;
}
public async ValueTask<TResult?> GetAsync<TState, TResult>(
Func<IQueryable<DpzApplication>, TState, IQueryable<TResult>> query,
TState state,
CancellationToken cancellationToken
)
{
return await Task.FromResult(query(repository.MongodbQueryable, state).FirstOrDefault());
}
public async ValueTask<string?> GetClientIdAsync(
DpzApplication application,
CancellationToken cancellationToken
)
{
return await ValueTask.FromResult(application.ClientId);
}
public async ValueTask<string?> GetClientSecretAsync(
DpzApplication application,
CancellationToken cancellationToken
)
{
return await ValueTask.FromResult(application.ClientSecret);
}
public async ValueTask<string?> GetClientTypeAsync(
DpzApplication application,
CancellationToken cancellationToken
)
{
return await ValueTask.FromResult(application.ClientType);
}
public ValueTask<string?> GetConsentTypeAsync(
DpzApplication application,
CancellationToken cancellationToken
)
{
return ValueTask.FromResult<string?>(string.Empty);
}
public ValueTask<string?> GetDisplayNameAsync(
DpzApplication application,
CancellationToken cancellationToken
)
{
return ValueTask.FromResult<string?>(application.DisplayName);
}
public ValueTask<ImmutableDictionary<CultureInfo, string>> GetDisplayNamesAsync(
DpzApplication application,
CancellationToken cancellationToken
)
{
return ValueTask.FromResult(ImmutableDictionary<CultureInfo, string>.Empty);
}
public ValueTask<string?> GetIdAsync(
DpzApplication application,
CancellationToken cancellationToken
)
{
return ValueTask.FromResult<string?>(application.Id.ToString());
}
public ValueTask<JsonWebKeySet?> GetJsonWebKeySetAsync(
DpzApplication application,
CancellationToken cancellationToken
)
{
return ValueTask.FromResult<JsonWebKeySet?>(null);
}
public async ValueTask<ImmutableArray<string>> GetPermissionsAsync(
DpzApplication application,
CancellationToken cancellationToken
)
{
ImmutableArray<string> result = [.. application.Permissions ?? []];
return await ValueTask.FromResult(result);
}
public async ValueTask<ImmutableArray<string>> GetPostLogoutRedirectUrisAsync(
DpzApplication application,
CancellationToken cancellationToken
)
{
return await ValueTask.FromResult(
application
.PostLogoutRedirectUri?.Split([';'], StringSplitOptions.RemoveEmptyEntries)
.ToImmutableArray() ?? []
);
}
public ValueTask<ImmutableDictionary<string, JsonElement>> GetPropertiesAsync(
DpzApplication application,
CancellationToken cancellationToken
)
{
return ValueTask.FromResult(ImmutableDictionary<string, JsonElement>.Empty);
}
public ValueTask<ImmutableArray<string>> GetRedirectUrisAsync(
DpzApplication application,
CancellationToken cancellationToken
)
{
return ValueTask.FromResult(
(
application.RedirectUris?.Split([';'], StringSplitOptions.RemoveEmptyEntries) ?? []
).ToImmutableArray()
);
}
public ValueTask<ImmutableArray<string>> GetRequirementsAsync(
DpzApplication application,
CancellationToken cancellationToken
)
{
return ValueTask.FromResult(ImmutableArray<string>.Empty);
}
public ValueTask<ImmutableDictionary<string, string>> GetSettingsAsync(
DpzApplication application,
CancellationToken cancellationToken
)
{
return ValueTask.FromResult(ImmutableDictionary<string, string>.Empty);
}
public ValueTask<DpzApplication> InstantiateAsync(CancellationToken cancellationToken)
{
return ValueTask.FromResult(new DpzApplication { Id = ObjectId.GenerateNewId() });
}
public IAsyncEnumerable<DpzApplication> ListAsync(
int? count,
int? offset,
CancellationToken cancellationToken
)
{
var options = new FindOptions<DpzApplication>();
if (offset.HasValue)
{
options.Skip = offset.Value;
}
if (count.HasValue)
{
options.Limit = count.Value;
}
return repository.SearchForAsync(
Builders<DpzApplication>.Filter.Empty,
options,
cancellationToken
);
}
public async IAsyncEnumerable<TResult> ListAsync<TState, TResult>(
Func<IQueryable<DpzApplication>, TState, IQueryable<TResult>> query,
TState state,
[EnumeratorCancellation] CancellationToken cancellationToken
)
{
var projected = query(repository.MongodbQueryable, state);
await foreach (
var element in projected.ToAsyncEnumerable().WithCancellation(cancellationToken)
)
{
yield return element;
}
}
public ValueTask SetApplicationTypeAsync(
DpzApplication application,
string? type,
CancellationToken cancellationToken
)
{
application.ApplicationType = type;
return ValueTask.CompletedTask;
}
public ValueTask SetClientIdAsync(
DpzApplication application,
string? identifier,
CancellationToken cancellationToken
)
{
application.ClientId = identifier;
return ValueTask.CompletedTask;
}
public ValueTask SetClientSecretAsync(
DpzApplication application,
string? secret,
CancellationToken cancellationToken
)
{
application.ClientSecret = secret;
return ValueTask.CompletedTask;
}
public ValueTask SetClientTypeAsync(
DpzApplication application,
string? type,
CancellationToken cancellationToken
)
{
application.ClientType = type;
return ValueTask.CompletedTask;
}
public ValueTask SetConsentTypeAsync(
DpzApplication application,
string? type,
CancellationToken cancellationToken
)
{
return ValueTask.CompletedTask;
}
public ValueTask SetDisplayNameAsync(
DpzApplication application,
string? name,
CancellationToken cancellationToken
)
{
application.DisplayName = name;
return ValueTask.CompletedTask;
}
public ValueTask SetDisplayNamesAsync(
DpzApplication application,
ImmutableDictionary<CultureInfo, string> names,
CancellationToken cancellationToken
)
{
return ValueTask.CompletedTask;
}
public ValueTask SetJsonWebKeySetAsync(
DpzApplication application,
JsonWebKeySet? set,
CancellationToken cancellationToken
)
{
return ValueTask.CompletedTask;
}
public ValueTask SetPermissionsAsync(
DpzApplication application,
ImmutableArray<string> permissions,
CancellationToken cancellationToken
)
{
application.Permissions = permissions.ToList();
return ValueTask.CompletedTask;
}
public async ValueTask SetPostLogoutRedirectUrisAsync(
DpzApplication application,
ImmutableArray<string> uris,
CancellationToken cancellationToken
)
{
application.PostLogoutRedirectUri = string.Join(';', uris);
await Task.CompletedTask;
}
public ValueTask SetPropertiesAsync(
DpzApplication application,
ImmutableDictionary<string, JsonElement> properties,
CancellationToken cancellationToken
)
{
var bson = BsonDocument.Parse(JsonSerializer.Serialize(properties));
application.Properties = bson;
return ValueTask.CompletedTask;
}
public ValueTask SetRedirectUrisAsync(
DpzApplication application,
ImmutableArray<string> uris,
CancellationToken cancellationToken
)
{
application.RedirectUris = string.Join(';', uris);
return ValueTask.CompletedTask;
}
public ValueTask SetRequirementsAsync(
DpzApplication application,
ImmutableArray<string> requirements,
CancellationToken cancellationToken
)
{
return ValueTask.CompletedTask;
}
public ValueTask SetSettingsAsync(
DpzApplication application,
ImmutableDictionary<string, string> settings,
CancellationToken cancellationToken
)
{
return ValueTask.CompletedTask;
}
public async ValueTask UpdateAsync(
DpzApplication application,
CancellationToken cancellationToken
)
{
// 不允许修改 id ClientId ClientSecret
var update = Builders<DpzApplication>
.Update.Set(x => x.DisplayName, application.DisplayName)
.Set(x => x.RedirectUris, application.RedirectUris)
.Set(x => x.PostLogoutRedirectUri, application.PostLogoutRedirectUri)
.Set(x => x.ApplicationType, application.ApplicationType)
.Set(x => x.ClientType, application.ClientType)
.Set(x => x.Permissions, application.Permissions)
.Set(x => x.Properties, application.Properties);
await repository.UpdateAsync(x => x.Id == application.Id, update, cancellationToken);
}
}
上述代码定义了一个名为 DpzApplicationStore 的类,它实现了 IOpenIddictApplicationStore<DpzApplication> 接口。这个类主要用于管理与 OpenIddict 应用程序相关的操作,具体功能如下:
计数操作:
CountAsync: 计算存储中的应用程序数量。CountAsync<TResult>: 计算符合自定义查询条件的应用程序数量。创建和删除应用程序:
CreateAsync: 创建一个新的应用程序并将其插入到存储中。DeleteAsync: 根据应用程序的 ID 删除应用程序。查找应用程序:
FindByIdAsync: 根据应用程序的 ID 查找应用程序。FindByClientIdAsync: 根据客户端 ID 查找应用程序。FindByPostLogoutRedirectUriAsync: 根据注销后重定向 URI 查找应用程序。FindByRedirectUriAsync: 根据重定向 URI 查找应用程序。获取应用程序属性:
GetApplicationTypeAsync: 获取应用程序类型。GetClientIdAsync: 获取客户端 ID。GetClientSecretAsync: 获取客户端密钥。GetClientTypeAsync: 获取客户端类型。GetDisplayNameAsync: 获取显示名称。GetRedirectUrisAsync: 获取重定向 URI 列表。GetPostLogoutRedirectUrisAsync: 获取注销后重定向 URI 列表。GetPermissionsAsync: 获取应用程序的权限。设置应用程序属性:
SetApplicationTypeAsync: 设置应用程序类型。SetClientIdAsync: 设置客户端 ID。SetClientSecretAsync: 设置客户端密钥。SetDisplayNameAsync: 设置显示名称。SetRedirectUrisAsync: 设置重定向 URI 列表。SetPostLogoutRedirectUrisAsync: 设置注销后重定向 URI 列表。SetPermissionsAsync: 设置应用程序的权限。更新应用程序:
UpdateAsync: 更新应用程序的属性,但不允许修改 ID、客户端 ID 和客户端密钥。实例化应用程序:
InstantiateAsync: 创建一个新的 DpzApplication 实例,生成一个新的 ID。列出应用程序:
ListAsync: 列出所有应用程序,支持分页(通过 count 和 offset 参数)。ListAsync<TState, TResult>: 根据自定义查询列出应用程序。获取和设置其他属性:
GetJsonWebKeySetAsync: 获取 JSON Web 密钥集(目前返回 null)。GetPropertiesAsync: 获取应用程序的属性(目前返回空字典)。GetRequirementsAsync: 获取应用程序的要求(目前返回空数组)。GetSettingsAsync: 获取应用程序的设置(目前返回空字典)。async 和 await)来处理数据库操作,以提高性能和响应能力。ILogger 记录操作信息,便于调试和监控。ImmutableArray 和 ImmutableDictionary 来处理集合,确保数据的不可变性。DpzApplicationStore 类是一个用于管理 OpenIddict 应用程序的存储类,提供了创建、查找、更新和删除应用程序的功能,并支持异步操作和日志记录。它与 MongoDB 数据库交互,使用了现代 C# 的一些特性,如异步编程和不可变集合。
