Проверка разрешений ABP от претензий - PullRequest
0 голосов
/ 11 января 2019

Я использую ABP версии 3.9 для ASP.NET Core. У нас есть существующий экземпляр Identity Server 4, который предоставляет информацию о роли в форме заявок (через OIDC). Я хотел бы, среди прочего, подключиться к системе разрешений ABP для динамического меню. Поскольку я не использую локальную Identity Server 1 реализацию, я не вижу способа преобразовать утверждения в разрешения.

Моя мысль - использовать пользовательское промежуточное программное обеспечение для обработки следующим образом:

public class ClaimsToAbpPermissionsMiddleware
{
    private readonly RequestDelegate _next;

    public ClaimsToAbpPermissionsMiddleware(RequestDelegate next)
    {
        _next = next;
    }

    public async Task InvokeAsync(HttpContext context)
    {
        // Get user
        ClaimsPrincipal user = context.User;

        // foreach claim of type "role"
        var roleClaims = user.Claims.Where(claim => claim.Type == "role");
        foreach (Claim claim in roleClaims)
        {
            switch (claim.Value)
            {
                case "TestResults":
                    // Assign applicable permission
                    // ...
                    break;
                default:
                    break;
            }
        }

        // Call the next delegate/middleware in the pipeline
        await _next(context);
    }
}

Проблема в том, что я не знаю, как применять разрешения. Управление пользователями 2 предлагает использовать UserManager, который, по-видимому, обладает необходимой функциональностью.

Во-первых, Abp.ZeroCore не имеет этого класса. Могу ли я использовать Abp.Zero в приложении ASP.NET Core?

Во-вторых, похоже, что Abp.Authorization.Users.AbpUserManager имеет аналогичную функциональность. Могу ли я использовать это? Однако я не уверен, как внедрить это в Startup, так как для этого требуется несколько типов AbpUserManager<TRole, TUser>, и я не знаю, какие типы использовать.

Любая помощь будет оценена. Кроме того, то, что я пытаюсь выполнимо? Есть ли лучший подход?

Проблема в том, что я не использую Module Zero Управление пользователями 2 . Все наши пользователи находятся в отдельной реализации Identity Server ASP.NET, и я использую шаблон из ABP, который не включает модели / страницы для user / tenant / role, поэтому у меня нет типы для введения AbpUserManager<TRole, TUser>.

1 https://aspnetboilerplate.com/Pages/Documents/Zero/Identity-Server
2 https://aspnetboilerplate.com/Pages/Documents/Zero/User-Management

Обновление: Поэтому я реализовал IPermissionChecker согласно ответу ниже:

PermissionChecker (не влюблен в коммутатор, но собираюсь провести рефакторинг, как только он заработает):

public class PermissionChecker : IPermissionChecker, ITransientDependency
{
    private readonly IHttpContextAccessor _httpContextAccessor;

    public PermissionChecker(IHttpContextAccessor httpContextAccessor)
    {
        _httpContextAccessor = httpContextAccessor;
    }

    public  Task<bool> IsGrantedAsync(string permissionName)
    {
        bool isGranted = false;

        // Get user
        var user = _httpContextAccessor.HttpContext.User;

        // Get claims of type "role"
        var roleClaims = user.Claims.Where(claim => claim.Type == "role");

        // Check for applicable permission based on role permissions
        foreach (Claim claim in roleClaims)
        {
            switch (claim.Value)
            {
                case "TestResults":
                    // Assign applicable permission
                    // ...
                    if(permissionName.ToLowerInvariant() == "TestResults".ToLowerInvariant())
                    {
                        isGranted = true;
                    }
                    break;
                case "About":
                    // Assign applicable permission
                    // ...
                    if (permissionName.ToLowerInvariant() == "AboutView".ToLowerInvariant())
                    {
                        isGranted = true;
                    }
                    break;
                case "Account":
                    // Assign applicable permission
                    // ...
                    if (permissionName.ToLowerInvariant() == "AccountView".ToLowerInvariant())
                    {
                        isGranted = true;
                    }
                    break;
                default:
                    break;
            }
            if (isGranted)
            {
                break;
            }
        }
        //return new Task<bool> 
        return Task.FromResult(isGranted);
    }

    public Task<bool> IsGrantedAsync(UserIdentifier user, string permissionName)
    {
        return IsGrantedAsync(permissionName);
    }
}

AuthorizationProvider:

public class MyAuthProvider : AuthorizationProvider
{
    public override void SetPermissions(IPermissionDefinitionContext context)
    {
        var about = context.CreatePermission("AboutView");
        var account = context.CreatePermission("AccountView");
        var testResults = context.CreatePermission("TestResults");
    }
}

Инициализация модуля:

public class CentralPortalCoreModule : AbpModule
{
    public override void PreInitialize()
    {
        Configuration.Auditing.IsEnabledForAnonymousUsers = true;

        CentralPortalLocalizationConfigurer.Configure(Configuration.Localization);
        IocManager.Register<IPermissionChecker, PermissionChecker>(DependencyLifeStyle.Transient);
        Configuration.Authorization.Providers.Add<MyAuthProvider>();
    }

    public override void Initialize()
    {
        IocManager.RegisterAssemblyByConvention(typeof(CentralPortalCoreModule).GetAssembly());
    }
}

Поставщик навигации:

public override void SetNavigation(INavigationProviderContext context)
    {
        context.Manager.MainMenu
            .AddItem(
                new MenuItemDefinition(
                    PageNames.Home,
                    L("HomePage"),
                    url: "",
                    icon: "fa fa-home"
                    )
            ).AddItem(
                new MenuItemDefinition(
                    PageNames.About,
                    L("About"),
                    url: "Home/About",
                    icon: "fa fa-info",
                    requiredPermissionName: "AboutView",
                    requiresAuthentication: true
                    )
            ).AddItem(
                new MenuItemDefinition(
                "Results",
                L("Results"),
                url: "Results",
                icon: "fa fa-tasks",
                requiredPermissionName: "TestResults"
                )
            )
            .AddItem(
                new MenuItemDefinition(
                    PageNames.Account,
                    L("Account"),
                    url: "Account",
                    icon: "fa fa-info",
                    requiredPermissionName:"AccountView",
                    requiresAuthentication: true

                    )

            )
            .AddItem(
                new MenuItemDefinition(
                    PageNames.Contact,
                    L("Contact"),
                    url: "Contact",
                    icon: "fa fa-info"
                    )
            );
    }

Добавление точек останова показывает, что PermissionChecker инициализируется так же, как и AuthProvider. К сожалению, навигация не показывает защищенные элементы, несмотря на то, что я прошел проверку подлинности и имею действительные заявки на роль. Метод IsGrantedAsync никогда не вызывается. Я попытался установить элементы навигации с помощью requireAuthentication = true и false, но ничего не изменилось.

Я что-то упустил?

1 Ответ

0 голосов
/ 11 января 2019

Ну, вы обращаетесь к документации по Module Zero, но не используете Module Zero.

Если вы не храните пользователей, тогда может не иметь смысла хранить разрешения пользователей.

Вы можете реализовать IPermissionChecker для проверки разрешений по заявкам.

public class PermissionChecker : IPermissionChecker, ITransientDependency
{
    private readonly IHttpContextAccessor _httpContextAccessor;

    public PermissionChecker(IHttpContextAccessor httpContextAccessor)
    {
        _httpContextAccessor = httpContextAccessor;
    }

    public async Task<bool> IsGrantedAsync(string permissionName)
    {
        // Get user
        var user = _httpContextAccessor.HttpContext.User;

        // Get claims of type "role"
        var roleClaims = user.Claims.Where(claim => claim.Type == "role");

        // Check for applicable permission based on role permissions
        // ...
    }

    public Task<bool> IsGrantedAsync(UserIdentifier user, string permissionName)
    {
        return IsGrantedAsync(permissionName);
    }
}

Поскольку AuthorizationHelper проверяет AbpSession.UserId, вам придется переопределить его метод.

public class NonUserAuthorizationHelper : AuthorizationHelper
{
    private readonly IAuthorizationConfiguration _authConfiguration

    public NonUserAuthorizationHelper(IFeatureChecker featureChecker, IAuthorizationConfiguration authConfiguration)
        : base(featureChecker, authConfiguration)
    {
        _authConfiguration = authConfiguration;
    }

    public override async Task AuthorizeAsync(IEnumerable<IAbpAuthorizeAttribute> authorizeAttributes)
    {
        if (!_authConfiguration.IsEnabled)
        {
            return;
        }

        // if (!AbpSession.UserId.HasValue)
        // {
        //     throw new AbpAuthorizationException(
        //         LocalizationManager.GetString(AbpConsts.LocalizationSourceName, "CurrentUserDidNotLoginToTheApplication")
        //     );
        // }

        foreach (var authorizeAttribute in authorizeAttributes)
        {
            await PermissionChecker.AuthorizeAsync(authorizeAttribute.RequireAllPermissions, authorizeAttribute.Permissions);
        }
    }
}

А затем замените его в методе PreInitialize вашего *.Core модуля.

// using Abp.Configuration.Startup;

public override void PreInitialize()
{
    Configuration.ReplaceService<IAuthorizationHelper, NonUserAuthorizationHelper>();
}
...