如何动态添加具有asp.net身份权限的新角色 [英] How to dynamically adding new roles with permissions in asp.net identity

查看:45
本文介绍了如何动态添加具有asp.net身份权限的新角色的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有自定义用户,角色,用户存储,角色存储.我可以进行身份​​验证操作.但是我要动态授权.添加新角色和关系角色以及权限,并将此角色设置为用户.我想要这样的东西

有关发现剃须刀页面的信息,请阅读在ASP.NET中发现控制器动作和剃刀页面.MVC核心

创建角色后,为用户分配角色并实施自定义授权过滤器,以检查天气用户是否可以访问请求的操作和控制器:

 公共类DynamicAuthorizationFilter:IAsyncAuthorizationFilter{私有只读ApplicationDbContext _dbContext;公共DynamicAuthorizationFilter(ApplicationDbContext dbContext){_dbContext = dbContext;}公共异步任务OnAuthorizationAsync(AuthorizationFilterContext上下文){如果(!IsProtectedAction(context))返回;如果(!IsUserAuthenticated(上下文)){context.Result =新的UnauthorizedResult();返回;}var actionId = GetActionId(上下文);var userName = context.HttpContext.User.Identity.Name;var role = await(来自_dbContext.Users中的用户在user.Id上的_dbContext.UserRoles中加入userRole等于userRole.UserIduserRole.RoleId上_dbContext.Roles中的join角色等于role.Id其中user.UserName == userName选择角色).ToListAsync();foreach(角色中的var角色){var accessList = JsonConvert.DeserializeObject< IEnumerable< MvcControllerInfo>>>(role.Access);如果(accessList.SelectMany(c => c.Actions).Any(a => a.Id == actionId))返回;}context.Result =新的ForbidResult();} 

我已经通过这种方式实现了基于角色的动态授权.有关详细信息,请查看ASP.NET Core 2.0中的基于角色的动态授权 github仓库.

I have custom user, role, userstore, rolestore. I can do authentication operations. But i want dynamic authorization. Adding new role and relation role and permissions and set this role to user. I want something like that https://imgur.com/jgl5xrs

Users model

namespace App.Models
{
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.ComponentModel.DataAnnotations;
    using System.ComponentModel.DataAnnotations.Schema;

    [Table("AppUsers")]
    public class User
    {
        [Key, Required]
        public Guid Id { get; set; }

        [Required, MaxLength(128)]
        public string UserName { get; set; }

        [Required, MaxLength(1024)]
        public string PasswordHash { get; set; }

        [Required, MaxLength(128)]
        public string Email { get; set; }

        [MaxLength(32)]
        public string EmployeeName { get; set; }

        public virtual ICollection<UserRole> UserRoles { get; set; }
    }
}

Role models

namespace App.Models
{
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.ComponentModel.DataAnnotations;
    using System.ComponentModel.DataAnnotations.Schema;

    [Table("Role")]
    public class Role
    {
        [Key, Required]
        public Guid Id { get; set; }

        [Required]
        public string RoleName { get; set; }

        public virtual ICollection<UserRole> UserRoles { get; set; }
    }
}

UserStore

namespace App.Identity
{
    using System;
    using System.Linq;
    using System.Threading;
    using System.Threading.Tasks;
    using App.Data;
    using App.Models;
    using Microsoft.AspNetCore.Identity;
    using Microsoft.EntityFrameworkCore.Extensions.Internal;

    public class UserStore : IUserStore<User>, IUserPasswordStore<User>
    {
        ...
    }
}

解决方案

When you are creating a new role, you need to discover all controllers and their actions and choose role can access which controllers and actions.

public class MvcControllerDiscovery : IMvcControllerDiscovery
{
    private List<MvcControllerInfo> _mvcControllers;
    private readonly IActionDescriptorCollectionProvider _actionDescriptorCollectionProvider;

    public MvcControllerDiscovery(IActionDescriptorCollectionProvider actionDescriptorCollectionProvider)
    {
        _actionDescriptorCollectionProvider = actionDescriptorCollectionProvider;
    }

    public IEnumerable<MvcControllerInfo> GetControllers()
    {
        if (_mvcControllers != null)
            return _mvcControllers;

        _mvcControllers = new List<MvcControllerInfo>();

        var items = _actionDescriptorCollectionProvider
            .ActionDescriptors.Items
            .Where(descriptor => descriptor.GetType() == typeof(ControllerActionDescriptor))
            .Select(descriptor => (ControllerActionDescriptor)descriptor)
            .GroupBy(descriptor => descriptor.ControllerTypeInfo.FullName)
            .ToList();

        foreach (var actionDescriptors in items)
        {
            if (!actionDescriptors.Any())
                continue;

            var actionDescriptor = actionDescriptors.First();
            var controllerTypeInfo = actionDescriptor.ControllerTypeInfo;
            var currentController = new MvcControllerInfo
            {
                AreaName = controllerTypeInfo.GetCustomAttribute<AreaAttribute>()?.RouteValue,
                DisplayName = controllerTypeInfo.GetCustomAttribute<DisplayNameAttribute>()?.DisplayName,
                Name = actionDescriptor.ControllerName,
            };

            var actions = new List<MvcActionInfo>();
            foreach (var descriptor in actionDescriptors.GroupBy(a => a.ActionName).Select(g => g.First()))
            {
                var methodInfo = descriptor.MethodInfo;
                actions.Add(new MvcActionInfo
                {
                    ControllerId = currentController.Id,
                    Name = descriptor.ActionName,
                    DisplayName = methodInfo.GetCustomAttribute<DisplayNameAttribute>()?.DisplayName,
                });
            }

            currentController.Actions = actions;
            _mvcControllers.Add(currentController);
        }

        return _mvcControllers;
    }
}

in RoleController and Create action return list of all controllers:

public class RoleController : Controller
{
    private readonly IMvcControllerDiscovery _mvcControllerDiscovery;

    public RoleController(IMvcControllerDiscovery mvcControllerDiscovery)
    {
        _mvcControllerDiscovery = mvcControllerDiscovery;
    }

    // GET: Role/Create
    public ActionResult Create()
    {
        ViewData["Controllers"] = _mvcControllerDiscovery.GetControllers();

        return View();
    }
} 

Create role page will be something like this:

For discovering razor pages read Discovering controller actions and Razor Pages in ASP.NET MVC Core

After creating role, assign roles to user and implement custom authorization filter to check weather user can access requested action and controller:

public class DynamicAuthorizationFilter : IAsyncAuthorizationFilter
{
    private readonly ApplicationDbContext _dbContext;

    public DynamicAuthorizationFilter(ApplicationDbContext dbContext)
    {
        _dbContext = dbContext;
    }

    public async Task OnAuthorizationAsync(AuthorizationFilterContext context)
    {
        if (!IsProtectedAction(context))
            return;

        if (!IsUserAuthenticated(context))
        {
            context.Result = new UnauthorizedResult();
            return;
        }

        var actionId = GetActionId(context);
        var userName = context.HttpContext.User.Identity.Name;

        var roles = await (
            from user in _dbContext.Users
            join userRole in _dbContext.UserRoles on user.Id equals userRole.UserId
            join role in _dbContext.Roles on userRole.RoleId equals role.Id
            where user.UserName == userName
            select role
        ).ToListAsync();

        foreach (var role in roles)
        {
            var accessList = JsonConvert.DeserializeObject<IEnumerable<MvcControllerInfo>>(role.Access);
            if (accessList.SelectMany(c => c.Actions).Any(a => a.Id == actionId))
                return;
        }

        context.Result = new ForbidResult();
    }

I have implement dynamic role-based authorization in this way. for full detail take look at Dynamic Role-Based Authorization in ASP.NET Core 2.0 github repo.

这篇关于如何动态添加具有asp.net身份权限的新角色的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆