网站首页 网站源码
website
站点相关全部源代码,隐藏了一些关于服务器的信息
using System.Collections.Immutable;
using System.Globalization;
using System.Text.Json;
using Dpz.Core.MongodbAccess;
using Dpz.Core.Public.Entity.Auth;
using Microsoft.Extensions.Logging;
using MongoDB.Bson;
using MongoDB.Driver;
using MongoDB.Driver.Linq;
using OpenIddict.Abstractions;

namespace Dpz.Core.Auth.Service;

public sealed class DpzScopeStore(IRepository<DpzScope> repository, ILogger<DpzScopeStore> logger)
    : IOpenIddictScopeStore<DpzScope>
{
    public async ValueTask<long> CountAsync(CancellationToken cancellationToken)
    {
        logger.LogInformation("Counting scopes");
        return await repository.MongodbQueryable.LongCountAsync(
            cancellationToken: cancellationToken
        );
    }

    public async ValueTask<long> CountAsync<TResult>(
        Func<IQueryable<DpzScope>, IQueryable<TResult>> query,
        CancellationToken cancellationToken
    )
    {
        logger.LogInformation("Counting scopes with custom query");
        return await query(repository.MongodbQueryable)
            .LongCountAsync(cancellationToken: cancellationToken);
    }

    public async ValueTask CreateAsync(DpzScope scope, CancellationToken cancellationToken)
    {
        logger.LogInformation("Creating scope {Name} ({Id})", scope.Name, scope.Id);
        await repository.InsertAsync(scope, cancellationToken);
    }

    public async ValueTask DeleteAsync(DpzScope scope, CancellationToken cancellationToken)
    {
        logger.LogWarning("Deleting scope {Name} ({Id})", scope.Name, scope.Id);
        await repository.DeleteAsync(scope.Id, cancellationToken);
    }

    public async ValueTask<DpzScope?> FindByIdAsync(
        string identifier,
        CancellationToken cancellationToken
    )
    {
        logger.LogInformation("Find scope by id {Identifier}", identifier);
        if (ObjectId.TryParse(identifier, out var id))
        {
            return await repository.FindAsync(id, cancellationToken);
        }
        return null;
    }

    public async ValueTask<DpzScope?> FindByNameAsync(
        string name,
        CancellationToken cancellationToken
    )
    {
        logger.LogInformation("Find scope by name {Name}", name);
        return await repository
            .SearchFor(x => x.Name == name)
            .FirstOrDefaultAsync(cancellationToken);
    }

    public IAsyncEnumerable<DpzScope> FindByNamesAsync(
        ImmutableArray<string> names,
        CancellationToken cancellationToken
    )
    {
        logger.LogInformation("Find scopes by names (count={Count})", names.Length);
        if (names.IsDefaultOrEmpty)
        {
            return AsyncEnumerable.Empty<DpzScope>();
        }

        var filter = Builders<DpzScope>.Filter.In(x => x.Name, names);
        return repository.SearchForAsync(filter, cancellationToken);
    }

    public IAsyncEnumerable<DpzScope> FindByResourceAsync(
        string resource,
        CancellationToken cancellationToken
    )
    {
        logger.LogInformation("Find scopes by resource {Resource}", resource);
        var filter = Builders<DpzScope>.Filter.AnyEq(x => x.Resources, resource);
        return repository.SearchForAsync(filter, cancellationToken);
    }

    public async ValueTask<TResult?> GetAsync<TState, TResult>(
        Func<IQueryable<DpzScope>, TState, IQueryable<TResult>> query,
        TState state,
        CancellationToken cancellationToken
    )
    {
        logger.LogInformation("Get with custom query state={State}", state);
        return await Task.FromResult(query(repository.MongodbQueryable, state).FirstOrDefault());
    }

    public async ValueTask<string?> GetDescriptionAsync(
        DpzScope scope,
        CancellationToken cancellationToken
    )
    {
        logger.LogTrace("Get description of scope {Id}", scope.Id);
        return await ValueTask.FromResult(scope.Description);
    }

    public async ValueTask<ImmutableDictionary<CultureInfo, string>> GetDescriptionsAsync(
        DpzScope scope,
        CancellationToken cancellationToken
    )
    {
        logger.LogTrace("Get descriptions of scope {Id}", scope.Id);
        if (scope.Descriptions is null || scope.Descriptions.Count == 0)
        {
            return await ValueTask.FromResult(ImmutableDictionary<CultureInfo, string>.Empty);
        }

        var builder = ImmutableDictionary.CreateBuilder<CultureInfo, string>();
        foreach (var kv in scope.Descriptions)
        {
            try
            {
                builder[CultureInfo.GetCultureInfo(kv.Key)] = kv.Value;
            }
            catch
            {
                // 跳过无法解析的文化键
            }
        }
        return await ValueTask.FromResult(builder.ToImmutable());
    }

    public async ValueTask<string?> GetDisplayNameAsync(
        DpzScope scope,
        CancellationToken cancellationToken
    )
    {
        logger.LogTrace("Get display name of scope {Id}", scope.Id);
        return await ValueTask.FromResult(scope.DisplayName);
    }

    public async ValueTask<ImmutableDictionary<CultureInfo, string>> GetDisplayNamesAsync(
        DpzScope scope,
        CancellationToken cancellationToken
    )
    {
        logger.LogTrace("Get display names of scope {Id}", scope.Id);
        if (scope.DisplayNames is null || scope.DisplayNames.Count == 0)
        {
            return await ValueTask.FromResult(ImmutableDictionary<CultureInfo, string>.Empty);
        }

        var builder = ImmutableDictionary.CreateBuilder<CultureInfo, string>();
        foreach (var kv in scope.DisplayNames)
        {
            try
            {
                builder[CultureInfo.GetCultureInfo(kv.Key)] = kv.Value;
            }
            catch
            {
                // 跳过无法解析的文化键
            }
        }
        return await ValueTask.FromResult(builder.ToImmutable());
    }

    public async ValueTask<string?> GetIdAsync(DpzScope scope, CancellationToken cancellationToken)
    {
        logger.LogTrace("Get id of scope {Id}", scope.Id);
        return await ValueTask.FromResult(scope.Id.ToString());
    }

    public async ValueTask<string?> GetNameAsync(
        DpzScope scope,
        CancellationToken cancellationToken
    )
    {
        logger.LogTrace("Get name of scope {Id}", scope.Id);
        return await ValueTask.FromResult(scope.Name);
    }

    public async ValueTask<ImmutableDictionary<string, JsonElement>> GetPropertiesAsync(
        DpzScope scope,
        CancellationToken cancellationToken
    )
    {
        logger.LogTrace("Get properties of scope {Id}", scope.Id);
        if (scope.Properties is null)
        {
            return await ValueTask.FromResult(ImmutableDictionary<string, JsonElement>.Empty);
        }

        var json = scope.Properties.ToJson();
        using var doc = JsonDocument.Parse(json);
        var builder = ImmutableDictionary.CreateBuilder<string, JsonElement>();
        foreach (var prop in doc.RootElement.EnumerateObject())
        {
            builder[prop.Name] = prop.Value.Clone();
        }
        return await ValueTask.FromResult(builder.ToImmutable());
    }

    public async ValueTask<ImmutableArray<string>> GetResourcesAsync(
        DpzScope scope,
        CancellationToken cancellationToken
    )
    {
        logger.LogTrace("Get resources of scope {Id}", scope.Id);
        var list = scope.Resources ?? [];
        return await ValueTask.FromResult(ImmutableArray.CreateRange(list));
    }

    public async ValueTask<DpzScope> InstantiateAsync(CancellationToken cancellationToken)
    {
        logger.LogInformation("Instantiate new scope");
        return await ValueTask.FromResult(new DpzScope { Id = ObjectId.GenerateNewId() });
    }

    public IAsyncEnumerable<DpzScope> ListAsync(
        int? count,
        int? offset,
        CancellationToken cancellationToken
    )
    {
        logger.LogInformation(
            "List scopes with pagination: offset={Offset}, count={Count}",
            offset,
            count
        );
        var options = new FindOptions<DpzScope>();
        if (offset.HasValue)
        {
            options.Skip = offset.Value;
        }
        if (count.HasValue)
        {
            options.Limit = count.Value;
        }

        return repository.SearchForAsync(
            Builders<DpzScope>.Filter.Empty,
            options,
            cancellationToken
        );
    }

    public async IAsyncEnumerable<TResult> ListAsync<TState, TResult>(
        Func<IQueryable<DpzScope>, TState, IQueryable<TResult>> query,
        TState state,
        [System.Runtime.CompilerServices.EnumeratorCancellation] CancellationToken cancellationToken
    )
    {
        logger.LogInformation("List scopes with custom query state={State}", state);
        var projected = query(repository.MongodbQueryable, state);
        await foreach (
            var element in projected.ToAsyncEnumerable().WithCancellation(cancellationToken)
        )
        {
            yield return element;
        }
    }

    public async ValueTask SetDescriptionAsync(
        DpzScope scope,
        string? description,
        CancellationToken cancellationToken
    )
    {
        logger.LogInformation("Set description of scope {Id}", scope.Id);
        scope.Description = description;
        await ValueTask.CompletedTask;
    }

    public async ValueTask SetDescriptionsAsync(
        DpzScope scope,
        ImmutableDictionary<CultureInfo, string> descriptions,
        CancellationToken cancellationToken
    )
    {
        logger.LogInformation("Set descriptions of scope {Id}", scope.Id);
        scope.Descriptions = descriptions.ToDictionary(k => k.Key.Name, v => v.Value);
        await ValueTask.CompletedTask;
    }

    public async ValueTask SetDisplayNameAsync(
        DpzScope scope,
        string? name,
        CancellationToken cancellationToken
    )
    {
        logger.LogInformation("Set display name of scope {Id}", scope.Id);
        scope.DisplayName = name;
        await ValueTask.CompletedTask;
    }

    public async ValueTask SetDisplayNamesAsync(
        DpzScope scope,
        ImmutableDictionary<CultureInfo, string> names,
        CancellationToken cancellationToken
    )
    {
        logger.LogInformation("Set display names of scope {Id}", scope.Id);
        scope.DisplayNames = names.ToDictionary(k => k.Key.Name, v => v.Value);
        await ValueTask.CompletedTask;
    }

    public async ValueTask SetNameAsync(
        DpzScope scope,
        string? name,
        CancellationToken cancellationToken
    )
    {
        logger.LogInformation("Set name of scope {Id}", scope.Id);
        scope.Name = name;
        await ValueTask.CompletedTask;
    }

    public async ValueTask SetPropertiesAsync(
        DpzScope scope,
        ImmutableDictionary<string, JsonElement> properties,
        CancellationToken cancellationToken
    )
    {
        logger.LogInformation("Set properties of scope {Id}", scope.Id);
        if (properties.Count == 0)
        {
            scope.Properties = null;
            await ValueTask.CompletedTask;
            return;
        }

        var bson = new BsonDocument();
        foreach (var kv in properties)
        {
            bson[kv.Key] = BsonDocument.Parse(kv.Value.GetRawText());
        }
        scope.Properties = bson;
        await ValueTask.CompletedTask;
    }

    public async ValueTask SetResourcesAsync(
        DpzScope scope,
        ImmutableArray<string> resources,
        CancellationToken cancellationToken
    )
    {
        logger.LogInformation("Set resources of scope {Id}", scope.Id);
        scope.Resources = resources.IsDefault ? [] : resources.ToArray();
        await ValueTask.CompletedTask;
    }

    public async ValueTask UpdateAsync(DpzScope scope, CancellationToken cancellationToken)
    {
        logger.LogInformation("Updating scope {Name} ({Id})", scope.Name, scope.Id);
        await repository.UpdateAsync(scope, cancellationToken);
    }
}
⚠⚠    以下内容为AI分析的结果,请根据实际情况进行判断。

上述代码定义了一个名为 DpzScopeStore 的类,它实现了 IOpenIddictScopeStore<DpzScope> 接口。这个类主要用于管理与 OAuth2/OpenID Connect 相关的 "scope"(范围)对象。以下是代码的主要功能和结构的详细解释:

1. 类的构造函数

  • DpzScopeStore(IRepository<DpzScope> repository, ILogger<DpzScopeStore> logger):构造函数接受一个 IRepository<DpzScope> 类型的 repository 和一个 ILogger<DpzScopeStore> 类型的 loggerrepository 用于与 MongoDB 数据库进行交互,而 logger 用于记录日志。

2. 主要功能方法

  • 计数方法

    • CountAsync:返回数据库中所有 scope 的数量。
    • CountAsync<TResult>:根据自定义查询返回符合条件的 scope 数量。
  • 创建和删除

    • CreateAsync:创建一个新的 scope 并将其插入数据库。
    • DeleteAsync:根据 scope 的 ID 删除指定的 scope。
  • 查找方法

    • FindByIdAsync:根据 ID 查找 scope。
    • FindByNameAsync:根据名称查找 scope。
    • FindByNamesAsync:根据名称数组查找多个 scope。
    • FindByResourceAsync:根据资源查找 scope。
  • 获取属性

    • GetAsync:根据自定义查询获取 scope。
    • GetDescriptionAsyncGetDisplayNameAsync:获取 scope 的描述和显示名称。
    • GetResourcesAsync:获取 scope 关联的资源。
    • GetPropertiesAsync:获取 scope 的自定义属性。
  • 实例化和列出

    • InstantiateAsync:实例化一个新的 DpzScope 对象。
    • ListAsync:列出所有 scope,支持分页。
    • ListAsync<TState, TResult>:根据自定义查询列出 scope。
  • 设置属性

    • SetDescriptionAsyncSetDisplayNameAsyncSetNameAsync:设置 scope 的描述、显示名称和名称。
    • SetResourcesAsync:设置 scope 关联的资源。
    • SetPropertiesAsync:设置 scope 的自定义属性。
    • SetDescriptionsAsyncSetDisplayNamesAsync:设置多语言描述和显示名称。
  • 更新

    • UpdateAsync:更新现有的 scope。

3. 日志记录

在每个方法中,使用 logger 记录相关操作的信息,例如创建、删除、查找和更新 scope 的操作。这有助于在生产环境中进行调试和监控。

4. 异步编程

所有方法都使用 asyncValueTask,这表明它们是异步的,适合在高并发环境中使用,以提高性能。

5. 文化信息处理

在获取和设置描述和显示名称时,使用 ImmutableDictionary<CultureInfo, string> 来支持多语言,这使得系统能够处理不同文化的文本。

总结

DpzScopeStore 类是一个用于管理 OAuth2/OpenID Connect 中的 scope 的服务类,提供了创建、查找、更新和删除等基本操作,并且支持异步编程和多语言处理。它通过与 MongoDB 的交互来持久化这些操作,并通过日志记录来跟踪操作的执行情况。

loading