C# .NET核心自定义授权依赖项注入

C# .NET核心自定义授权依赖项注入,c#,dependency-injection,authorization,asp.net-core-webapi,C#,Dependency Injection,Authorization,Asp.net Core Webapi,我们有一个定制的授权方案,我正试图通过在.NETCore中进行单元测试和使用依赖注入来解决这个方案。让我解释一下设置: 我创建了一个接口IStsHttpClient和类StsHttpClient。此类连接到创建和解码令牌的内部web服务。这正好有一个方法“DecodeToken(string token)”,构造函数非常简单——它接受从DI加载的option对象 然后,我的AuthorizationHandler理论上只使用IStsHttpClient调用和解码令牌。我的问题是,基于在线示例,我

我们有一个定制的授权方案,我正试图通过在.NETCore中进行单元测试和使用依赖注入来解决这个方案。让我解释一下设置:

我创建了一个接口IStsHttpClient和类StsHttpClient。此类连接到创建和解码令牌的内部web服务。这正好有一个方法“DecodeToken(string token)”,构造函数非常简单——它接受从DI加载的option对象

然后,我的AuthorizationHandler理论上只使用IStsHttpClient调用和解码令牌。我的问题是,基于在线示例,我不知道如何正确指定/构建授权处理程序(请参见下面的代码)

此处的身份验证代码:

public class MyAuthorizationRequirement : AuthorizationHandler<MyAuthorizationRequirement >, IAuthorizationRequirement
{
    const string Bearer = "Bearer ";
    readonly IStsHttpClient _client;

    public BuzzStsAuthorizationRequirement([FromServices]IStsHttpClient client)
    {
        _client = client;           
    }

    protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, MyStsAuthorizationRequirement requirement)
    {
        /*  remaining code omitted -  but this will call IStsHttpClient.Decode() */
公共类MyAuthorizationRequirement:AuthorizationHandler,IAAuthorizationRequirement
{
const string Bearer=“Bearer”;
只读IStsHttpClient\u客户端;
公共BuzzsTSA授权要求([FromServices]ISTSHTPClient客户端)
{
_客户=客户;
}
受保护的重写异步任务HandleRequirementAsync(授权HandlerContext上下文,MySTSAuthorizationRequirementAsync)
{
/*省略其余代码-但这将调用IStsHttpClient.Decode()*/
我的Startup.cs

    public void ConfigureServices(IServiceCollection services)
    {
        services.Configure<StsHttpOptions>(Configuration.GetSection("StsConfigurationInfo"));
        services.AddScoped<IStsHttpClient , StsHttpClient >();
        services.AddAuthorization(options =>
        {
            options.AddPolicy("Authorize", policy =>
            {
                /* initialize this differently?? */
                policy.AddRequirements(new MyStsAuthorizationRequirement( /* somethign is needed here?? */));
            });
        });
services.AddDbContext<PokeflexContext>
(options =>    options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
        services.AddSingleton<IAuthorizationPolicyProvider, PermissionPolicyProvider>();
        services.AddScoped<IAuthorizationHandler, PermissionAuthorizationHandler>();
        services.AddIdentity<IdentityUser, IdentityRole>()
                .AddEntityFrameworkStores<PokeflexContext>()
                .AddUserManager<UserManager<IdentityUser>>()
                .AddDefaultTokenProviders();
public void配置服务(IServiceCollection服务)
{
services.Configure(Configuration.GetSection(“StsConfigurationInfo”);
services.addScope();
services.AddAuthorization(选项=>
{
options.AddPolicy(“授权”,策略=>
{
/*以不同的方式初始化它*/
policy.AddRequirements(新的mystAuthorizationRequirements(/*此处需要一些符号??*/);
});
});
尼古拉斯

您必须在此处分离处理程序和需求。此外,将DI内容保留在处理程序中。需求本身将是DTO或带有标记接口IAuthorizationRequirement的空类

要求:

public class MyAuthorizationRequirement : IAuthorizationRequirement
{

}
处理程序:

public class MyAuthorizationHandler : AuthorizationHandler<MyAuthorizationRequirement>
{
    const string Bearer = "Bearer ";
    readonly IStsHttpClient _client;

    public BuzzStsAuthorizationRequirement([FromServices]IStsHttpClient client)
    {
        _client = client;           
    }

    protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, MyAuthorizationRequirement requirement)
    {
    ...
    }
}
公共类MyAuthorizationHandler:AuthorizationHandler
{
const string Bearer=“Bearer”;
只读IStsHttpClient\u客户端;
公共BuzzsTSA授权要求([FromServices]ISTSHTPClient客户端)
{
_客户=客户;
}
受保护的重写异步任务HandleRequirementAsync(AuthorizationHandlerContext上下文,MyAuthorizationRequirementAsync)
{
...
}
}
配置:

 services.Configure<StsHttpOptions>(Configuration.GetSection("StsConfigurationInfo"));
        services.AddScoped<IStsHttpClient , StsHttpClient >();
        services.AddAuthorization(options =>
        {
            options.AddPolicy("Authorize", policy =>
            {               
                policy.AddRequirements(new MyAuthorizationRequirement());
            });
        });
services.Configure(Configuration.GetSection(“StsConfigurationInfo”);
services.addScope();
services.AddAuthorization(选项=>
{
options.AddPolicy(“授权”,策略=>
{               
policy.AddRequirements(新的MyAuthorizationRequirements());
});
});

对于其他希望在C#9 NetCore5中围绕现有权限处理程序包装授权的人,我找到了以下解决方案,允许我使用stock dependency injection容器将服务注入AuthorizationHandler

对我来说,这需要5个新类和对Startup.cs的一些更改

    public void ConfigureServices(IServiceCollection services)
    {
        services.Configure<StsHttpOptions>(Configuration.GetSection("StsConfigurationInfo"));
        services.AddScoped<IStsHttpClient , StsHttpClient >();
        services.AddAuthorization(options =>
        {
            options.AddPolicy("Authorize", policy =>
            {
                /* initialize this differently?? */
                policy.AddRequirements(new MyStsAuthorizationRequirement( /* somethign is needed here?? */));
            });
        });
services.AddDbContext<PokeflexContext>
(options =>    options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
        services.AddSingleton<IAuthorizationPolicyProvider, PermissionPolicyProvider>();
        services.AddScoped<IAuthorizationHandler, PermissionAuthorizationHandler>();
        services.AddIdentity<IdentityUser, IdentityRole>()
                .AddEntityFrameworkStores<PokeflexContext>()
                .AddUserManager<UserManager<IdentityUser>>()
                .AddDefaultTokenProviders();
以下是my PermissionPolicyProvider.cs,这将表示一般权限,而不是策略(稍后我将筛选权限)

使用系统数据;
使用System.Threading.Tasks;
使用App.Models;
使用App.Services.Permissions;
使用Microsoft.AspNetCore.Authorization;
使用Microsoft.AspNetCore.Identity;
名称空间应用程序权限
{
类PermissionAuthorizationHandler:AuthorizationHandler
{

private readonly AppUserManager

在这之后的一两天,我终于意识到我可以使用中间件来做我想做的事情。什么是
BuzzStsAuthorizationRequirement
?它似乎是一个没有返回类型的方法。不能是构造函数。
using System;
using System.Collections.Generic;
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;

namespace App.Permissions
{
    public class AppUserManager<TUser> : UserManager<TUser> where TUser : class
    {
        public IServiceProvider Services;

        public AppUserManager(IUserStore<TUser> store,
            IOptions<IdentityOptions> optionsAccessor, IPasswordHasher<TUser> passwordHasher,
            IEnumerable<IUserValidator<TUser>> userValidators,
            IEnumerable<IPasswordValidator<TUser>> passwordValidators,
            ILookupNormalizer keyNormalizer, IdentityErrorDescriber errors,
            IServiceProvider services, ILogger<UserManager<TUser>> logger)
            : base(store, optionsAccessor, passwordHasher, userValidators,
                passwordValidators, keyNormalizer, errors, services, logger)
        {
            Services = services;
        }
    }
}
using System;
using System.Collections.Generic;
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;

namespace App.Permissions
{
    public class AppUserManager<TUser> : UserManager<TUser> where TUser : class
    {
        public IServiceProvider Services;

        public AppUserManager(IUserStore<TUser> store,
            IOptions<IdentityOptions> optionsAccessor, IPasswordHasher<TUser> passwordHasher,
            IEnumerable<IUserValidator<TUser>> userValidators,
            IEnumerable<IPasswordValidator<TUser>> passwordValidators,
            ILookupNormalizer keyNormalizer, IdentityErrorDescriber errors,
            IServiceProvider services, ILogger<UserManager<TUser>> logger)
            : base(store, optionsAccessor, passwordHasher, userValidators,
                passwordValidators, keyNormalizer, errors, services, logger)
        {
            Services = services;
        }
    }
}
    services.AddDbContext<PokeflexContext>(options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
    services.AddTransient<PermissionService>();
    services.AddSingleton<IAuthorizationPolicyProvider, PermissionPolicyProvider>();
    services.AddScoped<IAuthorizationHandler, PermissionAuthorizationHandler>();
    services.AddIdentity<AppUser, IdentityRole>()
            .AddEntityFrameworkStores<PokeflexContext>()
            .AddUserManager<AppUserManager<AppUser>>()
            .AddDefaultTokenProviders();
    services.AddScoped(s => s.GetService<AppUserManager<AppUser>>());
using System.Threading.Tasks;
using App.Data;
using Microsoft.EntityFrameworkCore;

namespace App.Services.Permissions
{
    public class PermissionService
    {
        private PokeflexContext _dbContext;

        public PermissionService(PokeflexContext dbContext)
        {
            _dbContext = dbContext;
        }

        public virtual async Task<bool> Permitted(string permission)
        {
            return await _dbContext.AppUsers.AnyAsync();
        }
    }
}