网站首页 网站源码
website
站点相关全部源代码,隐藏了一些关于服务器的信息
using System.Collections.Immutable;
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 DpzAuthorizationStore(
    IRepository<DpzAuthorization> repository,
    ILogger<DpzAuthorizationStore> logger
) : IOpenIddictAuthorizationStore<DpzAuthorization>
{
    public async ValueTask<long> CountAsync(CancellationToken cancellationToken)
    {
        logger.LogInformation("Counting authorizations");
        return await repository.MongodbQueryable.LongCountAsync(
            cancellationToken: cancellationToken
        );
    }

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

    public async ValueTask CreateAsync(
        DpzAuthorization dpzAuthorization,
        CancellationToken cancellationToken
    )
    {
        logger.LogInformation("Creating authorization {Id}", dpzAuthorization.Id);
        await repository.InsertAsync(dpzAuthorization, cancellationToken);
    }

    public async ValueTask DeleteAsync(
        DpzAuthorization dpzAuthorization,
        CancellationToken cancellationToken
    )
    {
        logger.LogInformation("Deleting authorization {Id}", dpzAuthorization.Id);
        await repository.DeleteAsync(x => x.Id == dpzAuthorization.Id, cancellationToken);
    }

    public IAsyncEnumerable<DpzAuthorization> FindAsync(
        string? subject,
        string? client,
        string? status,
        string? type,
        ImmutableArray<string>? scopes,
        CancellationToken cancellationToken
    )
    {
        logger.LogInformation(
            "Find authorizations subject={Subject}, client={Client}, status={Status}, type={Type}",
            subject,
            client,
            status,
            type
        );
        var filter = Builders<DpzAuthorization>.Filter.Empty;

        if (!string.IsNullOrWhiteSpace(subject))
        {
            filter &= Builders<DpzAuthorization>.Filter.Eq(x => x.Subject, subject);
        }
        if (!string.IsNullOrWhiteSpace(client))
        {
            if (ObjectId.TryParse(client, out var appId))
            {
                filter &= Builders<DpzAuthorization>.Filter.Eq(x => x.ApplicationId, appId);
            }
            else
            {
                // 如果传入的是客户端Id字符串,这里无法直接反查ApplicationId,按存储模型仅支持ObjectId
                filter &= Builders<DpzAuthorization>.Filter.Where(_ => false);
            }
        }
        if (!string.IsNullOrWhiteSpace(status))
        {
            filter &= Builders<DpzAuthorization>.Filter.Eq(x => x.Status, status);
        }
        if (!string.IsNullOrWhiteSpace(type))
        {
            filter &= Builders<DpzAuthorization>.Filter.Eq(x => x.Type, type);
        }
        if (scopes is { IsDefaultOrEmpty: false })
        {
            filter &= Builders<DpzAuthorization>.Filter.All(x => x.Scopes!, scopes.Value);
        }

        return repository.SearchForAsync(filter, cancellationToken);
    }

    public IAsyncEnumerable<DpzAuthorization> FindByApplicationIdAsync(
        string identifier,
        CancellationToken cancellationToken
    )
    {
        logger.LogInformation("Find authorizations by application id {Identifier}", identifier);
        if (!ObjectId.TryParse(identifier, out var appId))
        {
            return AsyncEnumerable.Empty<DpzAuthorization>();
        }

        var filter = Builders<DpzAuthorization>.Filter.Eq(x => x.ApplicationId, appId);
        return repository.SearchForAsync(filter, cancellationToken);
    }

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

    public IAsyncEnumerable<DpzAuthorization> FindBySubjectAsync(
        string subject,
        CancellationToken cancellationToken
    )
    {
        logger.LogInformation("Find authorizations by subject {Subject}", subject);
        var filter = Builders<DpzAuthorization>.Filter.Eq(x => x.Subject, subject);
        return repository.SearchForAsync(filter, cancellationToken);
    }

    public async ValueTask<string?> GetApplicationIdAsync(
        DpzAuthorization dpzAuthorization,
        CancellationToken cancellationToken
    )
    {
        return await ValueTask.FromResult(dpzAuthorization.ApplicationId.ToString());
    }

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

    public async ValueTask<DateTimeOffset?> GetCreationDateAsync(
        DpzAuthorization dpzAuthorization,
        CancellationToken cancellationToken
    )
    {
        var result = dpzAuthorization.CreationDate is { } dt
            ? new DateTimeOffset(DateTime.SpecifyKind(dt, DateTimeKind.Utc))
            : (DateTimeOffset?)null;
        return await ValueTask.FromResult(result);
    }

    public async ValueTask<string?> GetIdAsync(
        DpzAuthorization dpzAuthorization,
        CancellationToken cancellationToken
    )
    {
        return await ValueTask.FromResult(dpzAuthorization.Id.ToString());
    }

    public async ValueTask<ImmutableDictionary<string, JsonElement>> GetPropertiesAsync(
        DpzAuthorization dpzAuthorization,
        CancellationToken cancellationToken
    )
    {
        if (dpzAuthorization.Properties is null)
        {
            return await ValueTask.FromResult(ImmutableDictionary<string, JsonElement>.Empty);
        }

        // 将BsonDocument序列化为Json再解析为字典
        var json = dpzAuthorization.Properties.ToJson();
        var doc = JsonDocument.Parse(json);

        var builder = ImmutableDictionary.CreateBuilder<string, JsonElement>();

        foreach (var property in doc.RootElement.EnumerateObject())
        {
            builder[property.Name] = property.Value.Clone();
        }

        return await ValueTask.FromResult(builder.ToImmutable());
    }

    public async ValueTask<ImmutableArray<string>> GetScopesAsync(
        DpzAuthorization dpzAuthorization,
        CancellationToken cancellationToken
    )
    {
        var list = dpzAuthorization.Scopes ?? [];
        return await ValueTask.FromResult(ImmutableArray.CreateRange(list));
    }

    public async ValueTask<string?> GetStatusAsync(
        DpzAuthorization dpzAuthorization,
        CancellationToken cancellationToken
    )
    {
        return await ValueTask.FromResult(dpzAuthorization.Status);
    }

    public async ValueTask<string?> GetSubjectAsync(
        DpzAuthorization dpzAuthorization,
        CancellationToken cancellationToken
    )
    {
        return await ValueTask.FromResult(dpzAuthorization.Subject);
    }

    public async ValueTask<string?> GetTypeAsync(
        DpzAuthorization dpzAuthorization,
        CancellationToken cancellationToken
    )
    {
        return await ValueTask.FromResult(dpzAuthorization.Type);
    }

    public async ValueTask<DpzAuthorization> InstantiateAsync(CancellationToken cancellationToken)
    {
        return await ValueTask.FromResult(new DpzAuthorization { Id = ObjectId.GenerateNewId() });
    }

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

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

    public async IAsyncEnumerable<TResult> ListAsync<TState, TResult>(
        Func<IQueryable<DpzAuthorization>, TState, IQueryable<TResult>> query,
        TState state,
        [System.Runtime.CompilerServices.EnumeratorCancellation] CancellationToken cancellationToken
    )
    {
        logger.LogInformation("List authorizations 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<long> PruneAsync(
        DateTimeOffset threshold,
        CancellationToken cancellationToken
    )
    {
        logger.LogInformation("Prune authorizations before {Threshold}", threshold);
        // 按创建时间早于阈值、且已无效状态,清理旧授权
        var builder = Builders<DpzAuthorization>.Filter;
        var filter = builder.And(
            builder.Lt(x => x.CreationDate, threshold.UtcDateTime),
            builder.Ne(x => x.Status, OpenIddictConstants.Statuses.Valid)
        );

        var result = await repository.Collection.DeleteManyAsync(filter, cancellationToken);
        return result.DeletedCount;
    }

    public async ValueTask<long> RevokeAsync(
        string? subject,
        string? client,
        string? status,
        string? type,
        CancellationToken cancellationToken
    )
    {
        logger.LogInformation(
            "Revoke authorizations subject={Subject}, client={Client}, status={Status}, type={Type}",
            subject,
            client,
            status,
            type
        );
        var builder = Builders<DpzAuthorization>.Filter;
        var filter = builder.Empty;

        if (!string.IsNullOrWhiteSpace(subject))
        {
            filter &= builder.Eq(x => x.Subject, subject);
        }
        if (!string.IsNullOrWhiteSpace(client) && ObjectId.TryParse(client, out var appId))
        {
            filter &= builder.Eq(x => x.ApplicationId, appId);
        }
        if (!string.IsNullOrWhiteSpace(status))
        {
            filter &= builder.Eq(x => x.Status, status);
        }
        if (!string.IsNullOrWhiteSpace(type))
        {
            filter &= builder.Eq(x => x.Type, type);
        }

        var update = Builders<DpzAuthorization>.Update.Set(
            x => x.Status,
            OpenIddictConstants.Statuses.Revoked
        );
        var result = await repository.Collection.UpdateManyAsync(
            filter,
            update,
            cancellationToken: cancellationToken
        );
        return result.ModifiedCount;
    }

    public async ValueTask<long> RevokeByApplicationIdAsync(
        string identifier,
        CancellationToken cancellationToken
    )
    {
        logger.LogInformation("Revoke authorizations by application id {Identifier}", identifier);
        if (!ObjectId.TryParse(identifier, out var appId))
        {
            return 0L;
        }
        var filter = Builders<DpzAuthorization>.Filter.Eq(x => x.ApplicationId, appId);
        var update = Builders<DpzAuthorization>.Update.Set(
            x => x.Status,
            OpenIddictConstants.Statuses.Revoked
        );
        var result = await repository.Collection.UpdateManyAsync(
            filter,
            update,
            cancellationToken: cancellationToken
        );
        return result.ModifiedCount;
    }

    public async ValueTask<long> RevokeBySubjectAsync(
        string subject,
        CancellationToken cancellationToken
    )
    {
        logger.LogInformation("Revoke authorizations by subject {Subject}", subject);
        var filter = Builders<DpzAuthorization>.Filter.Eq(x => x.Subject, subject);
        var update = Builders<DpzAuthorization>.Update.Set(
            x => x.Status,
            OpenIddictConstants.Statuses.Revoked
        );
        var result = await repository.Collection.UpdateManyAsync(
            filter,
            update,
            cancellationToken: cancellationToken
        );
        return result.ModifiedCount;
    }

    public async ValueTask SetApplicationIdAsync(
        DpzAuthorization dpzAuthorization,
        string? identifier,
        CancellationToken cancellationToken
    )
    {
        if (ObjectId.TryParse(identifier, out var appId))
        {
            dpzAuthorization.ApplicationId = appId;
        }
        await ValueTask.CompletedTask;
    }

    public async ValueTask SetCreationDateAsync(
        DpzAuthorization dpzAuthorization,
        DateTimeOffset? date,
        CancellationToken cancellationToken
    )
    {
        dpzAuthorization.CreationDate = date?.UtcDateTime;
        await ValueTask.CompletedTask;
    }

    public async ValueTask SetPropertiesAsync(
        DpzAuthorization dpzAuthorization,
        ImmutableDictionary<string, JsonElement> properties,
        CancellationToken cancellationToken
    )
    {
        if (properties.Count == 0)
        {
            dpzAuthorization.Properties = null;
            await ValueTask.CompletedTask;
            return;
        }

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

    public async ValueTask SetScopesAsync(
        DpzAuthorization dpzAuthorization,
        ImmutableArray<string> scopes,
        CancellationToken cancellationToken
    )
    {
        dpzAuthorization.Scopes = scopes.IsDefault ? Array.Empty<string>() : scopes.ToArray();
        await ValueTask.CompletedTask;
    }

    public async ValueTask SetStatusAsync(
        DpzAuthorization dpzAuthorization,
        string? status,
        CancellationToken cancellationToken
    )
    {
        dpzAuthorization.Status = status;
        await ValueTask.CompletedTask;
    }

    public async ValueTask SetSubjectAsync(
        DpzAuthorization dpzAuthorization,
        string? subject,
        CancellationToken cancellationToken
    )
    {
        dpzAuthorization.Subject = subject;
        await ValueTask.CompletedTask;
    }

    public async ValueTask SetTypeAsync(
        DpzAuthorization dpzAuthorization,
        string? type,
        CancellationToken cancellationToken
    )
    {
        dpzAuthorization.Type = type;
        await ValueTask.CompletedTask;
    }

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

上述代码定义了一个名为 DpzAuthorizationStore 的类,它实现了 IOpenIddictAuthorizationStore<DpzAuthorization> 接口。这个类主要用于管理与授权相关的操作,特别是在使用 MongoDB 作为数据存储的情况下。以下是代码的主要功能和结构的详细解释:

主要功能

  1. 计数操作:

    • CountAsync: 计算存储中的授权数量。
    • CountAsync<TResult>: 根据自定义查询计算授权数量。
  2. 创建和删除授权:

    • CreateAsync: 创建新的授权记录。
    • DeleteAsync: 根据授权对象的 ID 删除授权记录。
  3. 查找授权:

    • FindAsync: 根据多个条件(如 subject、client、status、type 和 scopes)查找授权记录。
    • FindByApplicationIdAsync: 根据应用程序 ID 查找授权记录。
    • FindByIdAsync: 根据授权 ID 查找单个授权记录。
    • FindBySubjectAsync: 根据 subject 查找授权记录。
  4. 获取授权属性:

    • GetApplicationIdAsync: 获取授权的应用程序 ID。
    • GetCreationDateAsync: 获取授权的创建日期。
    • GetIdAsync: 获取授权的 ID。
    • GetPropertiesAsync: 获取授权的附加属性。
    • GetScopesAsync: 获取授权的作用域。
    • GetStatusAsync: 获取授权的状态。
    • GetSubjectAsync: 获取授权的 subject。
    • GetTypeAsync: 获取授权的类型。
  5. 实例化和列出授权:

    • InstantiateAsync: 创建一个新的 DpzAuthorization 实例。
    • ListAsync: 列出所有授权记录,支持分页。
    • ListAsync<TState, TResult>: 根据自定义查询列出授权记录。
  6. 撤销和修剪授权:

    • RevokeAsync: 撤销符合条件的授权记录。
    • RevokeByApplicationIdAsync: 根据应用程序 ID 撤销授权。
    • RevokeBySubjectAsync: 根据 subject 撤销授权。
    • PruneAsync: 删除创建日期早于指定阈值且状态无效的授权记录。
  7. 设置授权属性:

    • SetApplicationIdAsync: 设置授权的应用程序 ID。
    • SetCreationDateAsync: 设置授权的创建日期。
    • SetPropertiesAsync: 设置授权的附加属性。
    • SetScopesAsync: 设置授权的作用域。
    • SetStatusAsync: 设置授权的状态。
    • SetSubjectAsync: 设置授权的 subject。
    • SetTypeAsync: 设置授权的类型。
  8. 更新授权:

    • UpdateAsync: 更新现有的授权记录。

代码结构

  • 构造函数: 接受一个 IRepository<DpzAuthorization> 和一个 ILogger<DpzAuthorizationStore>,用于数据访问和日志记录。
  • 异步方法: 许多方法使用 ValueTaskIAsyncEnumerable,以支持异步编程模型,优化性能。
  • MongoDB 查询: 使用 MongoDB.Driver 提供的构建器来构建查询和更新操作,确保与 MongoDB 的交互高效且安全。

总结

DpzAuthorizationStore 类是一个用于管理授权的存储库,提供了创建、查找、更新、删除和撤销授权的功能。它利用 MongoDB 作为后端存储,并通过日志记录提供了操作的可追踪性。这个类在实现 OAuth2 或 OpenID Connect 等身份验证和授权协议时非常有用。

loading