使用ASP.NET Core Identity 3的用户角色权限 [英] Users Roles Permissions using ASP.NET Core Identity 3

查看:84
本文介绍了使用ASP.NET Core Identity 3的用户角色权限的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我陷入了一个我想在asp.net mvc核心应用程序中提供的解决方案.我想利用新的基于Claims的方法为Web应用程序中的标准用户,角色和权限提供解决方案.

我在这里一直遵循Ben Foster的逻辑( http://benfoster. io/blog/asp-net-identity-role-claims ).在下面的代码(演示质量)中,我说明了我的方法,我将对其进行评论以帮助展示我的快速而肮脏的测试解决方案.

我面临的挑战是,它不起作用.

//注意:我已经找到了该错误,并将为以后寻求类似解决方案的用户提供说明.

种子类:这是一种快速又肮脏的解决方案,用于使用两个新用户,两个角色以及其中一个角色的某些声明为数据库播种.我将其作为测试应用程序进行了学习,以学习声明方法来管理我的应用程序的授权.我的完整解决方案将为每个租户提供一种通过UI创建自己的角色,将1个或多个声明与该角色相关联,然后将角色分配给用户的方法.我想为租户提供一种管理自己的用户以及他们可以做什么或不能做什么的方法.这是基于声明的方法的简单实现,因为声明比与策略的1:1关系具有更多的功能.

public class DbInitializer
{
    private ApplicationDbContext _context;
    private RoleManager<ApplicationRole> _roleManager;
    private UserManager<ApplicationUser> _userManager;

    public DbInitializer(ApplicationDbContext context,RoleManager<ApplicationRole> roleManager, UserManager<ApplicationUser> userManager)
    {
        _roleManager = roleManager;
        _userManager = userManager;
        _context = context;

    }

    public async Task Initialize()
    {
        //RoleManager<IdentityRole> roleManager = new RoleManager<IdentityRole>();
        //UserManager<ApplicationUser> userManager = new UserManager<ApplicationUser>();

        _context.Database.EnsureCreated();

        // Look for any students.
        if (!_context.Users.Any())
        {
            //create user and admin role

            ApplicationUser adminUser = new ApplicationUser();

            adminUser.Email = "admin@company.com";
            adminUser.UserName = "Admin";

            var result = await _userManager.CreateAsync(adminUser, "Password-1");

            var newAdminUser = await _userManager.FindByEmailAsync(adminUser.Email);

            ApplicationRole adminRole = new ApplicationRole();

            adminRole.Name = "Admin";
            adminRole.Description = "This is the admin role.";

            await _roleManager.CreateAsync(adminRole);

            await _roleManager.AddClaimAsync(adminRole, new Claim("Can add roles", "add.role"));
            await _roleManager.AddClaimAsync(adminRole, new Claim("Can delete roles", "delete.role"));
            await _roleManager.AddClaimAsync(adminRole, new Claim("Can edit roles", "edit.role"));

            await _userManager.AddToRoleAsync(newAdminUser, adminRole.Name);

            //create user and basic role

            ApplicationUser basicUser = new ApplicationUser();

            basicUser.Email = "basic@company.com";
            basicUser.UserName = "Basic";

            var resultBasic = await _userManager.CreateAsync(basicUser, "Password-1");

            var newBasicUser = await _userManager.FindByEmailAsync(basicUser.Email);

            ApplicationRole basicRole = new ApplicationRole();

            basicRole.Name = "Basic";
            basicRole.Description = "This is the basic role.";

            await _roleManager.CreateAsync(basicRole);

            //await _roleManager.AddClaimAsync(basicRole, new Claim("Can add roles", "add.role"));
            //await _roleManager.AddClaimAsync(basicRole, new Claim("Can delete roles", "delete.role"));
            //await _roleManager.AddClaimAsync(basicRole, new Claim("Can edit roles", "edit.role"));

            await _userManager.AddToRoleAsync(newBasicUser, basicRole.Name);

            await _context.SaveChangesAsync();
        }

    }
 }
}

Startup.CS:创建我的用户,角色和声明(并将它们关联)之后,我需要在Startup.cs类Confirgure Services方法中注册策略".这使我可以将索赔映射到一个或多个策略.

 public void ConfigureServices(IServiceCollection services)
    {
        // Add framework services.
        services.AddDbContext<ApplicationDbContext>(options =>
            options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));

        services.AddIdentity<ApplicationUser, ApplicationRole>()
            .AddEntityFrameworkStores<ApplicationDbContext>()
            .AddDefaultTokenProviders();


        services.AddAuthorization(options =>
        {
            options.AddPolicy("Add Role",
                policy => policy.RequireClaim("Can add roles", "add.role"));
            options.AddPolicy("Edit Role",
                policy => policy.RequireClaim("Can edit roles", "edit.role"));
            options.AddPolicy("Delete Role",
                policy => policy.RequireClaim("Can delete roles", "delete.role"));
        });

        services.AddMvc();

        services.AddTransient<DbInitializer>();

        // Add application services.
        services.AddTransient<IEmailSender, AuthMessageSender>();
        services.AddTransient<ISmsSender, AuthMessageSender>();
    }

视图:在我的用例中,我想限制没有与分配给他们的角色相关联的可以添加角色"声明的任何用户的添加角色"按钮.其余的视图代码无关.我遇到的问题是,我将声明名称作为第二个参数传递给AuthorizationService.AuthorizeAsync,而不是与声明相关联的策略"名称.此后,我在下面对其进行了纠正.

@model IEnumerable<ApplicationRoleListViewModel>
@using HailMarry.Models
@using Microsoft.AspNetCore.Authorization
@inject IAuthorizationService AuthorizationService

<br />
<div class="top-buffer"></div>
<div class="panel panel-primary">
<div class="panel-heading panel-head">Application Roles</div>
<div class="panel-body">
    <div class="btn-group">

         //Mistake
        //@if (await AuthorizationService.AuthorizeAsync(User, "Can add roles"))
         //Fix
         @if (await AuthorizationService.AuthorizeAsync(User, "Add Role"))
        {
            <a id="createRoleButton" asp-action="AddRole" asp-controller="ApplicationRole" class="btn btn-primary">
                <i class="glyphicon glyphicon-plus"></i>  Add Role
            </a>
        }
....

最终结果:我有一个用户"admin@company.com",该用户已分配给具有可以添加角色"声明的角色"Admin".一个角色可以有任意多个声明.我创建了一个策略,该策略具有与我通过可注入的IAuthorizationService AuthorizationService在视图中检查的可以添加角色"相同的主张.如果用户没有将此声明分配给他们的角色,则返回true或false的策略检查将不会显示添加角色的按钮.借助新的.net核心DI中间件,可以通过DI将相同的策略检查逻辑添加到控制器或任何其他资源.通过整个练习,我了解了Identity 3的功能,该功能可以利用诸如业务逻辑检查之类的功能.不错的东西,尽管那里的作者确实需要更多示例来帮助我们更快地掌握内容.无论如何,希望这可以帮助将来的开发人员寻找类似的解决方案.

解决方案

我发现了问题,我在视图中引用了声明名称"与策略名称...

我将在上面添加注释以说明错误并显示我在做什么.感谢Ben和ASP.Net提供了超过4.5的改进的授权解决方案.

I'm stuck on a solution that I would like to provide in an asp.net mvc core application. I would like to provide a solution to the standard User, Roles, Permissions in a web application leveraging the new Claims based approach.

I've been following Ben Foster's logic here (http://benfoster.io/blog/asp-net-identity-role-claims). In the code below (demo quality) I illustrate my methodology which I will comment to help show my quick and dirty test solution.

The challenge I have is, that its not working.

//NOTE: I have found the bug and will comment where I went wrong for future users looking for a similar solution.

Seed Class: This is a quick and dirty solution to seed the database with two new users, two roles and some claims for one of the roles. I did this as its a test app to learn the claims approach to managing authorization for my application. My full solution will provide a way for each Tenant to create their own roles via the UI, associate 1 or many claims to the role(s), then assign a role to a user. I wanted to provide a way for tenants to manage their own users and what they can or cannot do. This is a simple implementation of the claims based approach, as claims have a lot more power than 1:1 relations with policies.

public class DbInitializer
{
    private ApplicationDbContext _context;
    private RoleManager<ApplicationRole> _roleManager;
    private UserManager<ApplicationUser> _userManager;

    public DbInitializer(ApplicationDbContext context,RoleManager<ApplicationRole> roleManager, UserManager<ApplicationUser> userManager)
    {
        _roleManager = roleManager;
        _userManager = userManager;
        _context = context;

    }

    public async Task Initialize()
    {
        //RoleManager<IdentityRole> roleManager = new RoleManager<IdentityRole>();
        //UserManager<ApplicationUser> userManager = new UserManager<ApplicationUser>();

        _context.Database.EnsureCreated();

        // Look for any students.
        if (!_context.Users.Any())
        {
            //create user and admin role

            ApplicationUser adminUser = new ApplicationUser();

            adminUser.Email = "admin@company.com";
            adminUser.UserName = "Admin";

            var result = await _userManager.CreateAsync(adminUser, "Password-1");

            var newAdminUser = await _userManager.FindByEmailAsync(adminUser.Email);

            ApplicationRole adminRole = new ApplicationRole();

            adminRole.Name = "Admin";
            adminRole.Description = "This is the admin role.";

            await _roleManager.CreateAsync(adminRole);

            await _roleManager.AddClaimAsync(adminRole, new Claim("Can add roles", "add.role"));
            await _roleManager.AddClaimAsync(adminRole, new Claim("Can delete roles", "delete.role"));
            await _roleManager.AddClaimAsync(adminRole, new Claim("Can edit roles", "edit.role"));

            await _userManager.AddToRoleAsync(newAdminUser, adminRole.Name);

            //create user and basic role

            ApplicationUser basicUser = new ApplicationUser();

            basicUser.Email = "basic@company.com";
            basicUser.UserName = "Basic";

            var resultBasic = await _userManager.CreateAsync(basicUser, "Password-1");

            var newBasicUser = await _userManager.FindByEmailAsync(basicUser.Email);

            ApplicationRole basicRole = new ApplicationRole();

            basicRole.Name = "Basic";
            basicRole.Description = "This is the basic role.";

            await _roleManager.CreateAsync(basicRole);

            //await _roleManager.AddClaimAsync(basicRole, new Claim("Can add roles", "add.role"));
            //await _roleManager.AddClaimAsync(basicRole, new Claim("Can delete roles", "delete.role"));
            //await _roleManager.AddClaimAsync(basicRole, new Claim("Can edit roles", "edit.role"));

            await _userManager.AddToRoleAsync(newBasicUser, basicRole.Name);

            await _context.SaveChangesAsync();
        }

    }
 }
}

Startup.CS: After creating my users, roles and claims (and associating them), I needed to register the 'Policies' in the Startup.cs class Confirgure Services method. This allows me to map the claims to a Policy or Policies.

 public void ConfigureServices(IServiceCollection services)
    {
        // Add framework services.
        services.AddDbContext<ApplicationDbContext>(options =>
            options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));

        services.AddIdentity<ApplicationUser, ApplicationRole>()
            .AddEntityFrameworkStores<ApplicationDbContext>()
            .AddDefaultTokenProviders();


        services.AddAuthorization(options =>
        {
            options.AddPolicy("Add Role",
                policy => policy.RequireClaim("Can add roles", "add.role"));
            options.AddPolicy("Edit Role",
                policy => policy.RequireClaim("Can edit roles", "edit.role"));
            options.AddPolicy("Delete Role",
                policy => policy.RequireClaim("Can delete roles", "delete.role"));
        });

        services.AddMvc();

        services.AddTransient<DbInitializer>();

        // Add application services.
        services.AddTransient<IEmailSender, AuthMessageSender>();
        services.AddTransient<ISmsSender, AuthMessageSender>();
    }

View: In my use case, I wanted to restrict the 'Add Role' button from any user that doesn't have the "Can add roles" claim associated with the role they are assigned to. The rest of the view code is not relevant. The issue I ran into is that I passed in the claim name to the AuthorizationService.AuthorizeAsync as a second parameter vs the 'Policy' name which has the claim associated to it. I've since corrected it below.

@model IEnumerable<ApplicationRoleListViewModel>
@using HailMarry.Models
@using Microsoft.AspNetCore.Authorization
@inject IAuthorizationService AuthorizationService

<br />
<div class="top-buffer"></div>
<div class="panel panel-primary">
<div class="panel-heading panel-head">Application Roles</div>
<div class="panel-body">
    <div class="btn-group">

         //Mistake
        //@if (await AuthorizationService.AuthorizeAsync(User, "Can add roles"))
         //Fix
         @if (await AuthorizationService.AuthorizeAsync(User, "Add Role"))
        {
            <a id="createRoleButton" asp-action="AddRole" asp-controller="ApplicationRole" class="btn btn-primary">
                <i class="glyphicon glyphicon-plus"></i>  Add Role
            </a>
        }
....

End Result: I have a user "admin@company.com" which is assigned to a role "Admin" which has a claim "Can add roles". A role can have any number of claims. I created a Policy which has the same claim "Can add roles" that I checked in the View via the injectable IAuthorizationService AuthorizationService. If the user does not have this claim assigned to their role, then the policy check which returns true or false will not show the button to add the role. This same policy checking logic can be added to a controller, or any other resource via DI thanks to the new .net core DI middleware. Through this entire exercise, I learned the power of Identity 3, which can harness things like business logic checking. Pretty sweet stuff, although the writers out there really need more examples to help us get to the meat faster. Anyhow, hope this helps future developers looking for a similar solution.

解决方案

I found the issue, I referenced the claim 'name' vs the policy name in the view...

I'll add notes above to illustrate the mistake and to show what I'm doing. Pretty powerful stuff, thanks to Ben and ASP.Net for an improved authorization solution over 4.5.

这篇关于使用ASP.NET Core Identity 3的用户角色权限的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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