web-dev-qa-db-ja.com

ASP.NET Core Identity3を使用したユーザーロールのアクセス許可

私はasp.netmvcコアアプリケーションで提供したいソリューションに固執しています。新しいクレームベースのアプローチを活用して、Webアプリケーションの標準のユーザー、ロール、アクセス許可にソリューションを提供したいと思います。

私はここでBenFosterのロジックに従っています( http://benfoster.io/blog/asp-net-identity-role-claims )。以下のコード(デモ品質)では、私の方法論を説明します。これは、私の迅速で汚いテストソリューションを示すのに役立つようにコメントします。

私が抱えている課題は、それが機能しないことです。

//注:バグを発見しました。同様の解決策を探している将来のユーザーのために、どこが間違っていたかをコメントします。

シードクラス:これは、2人の新しいユーザー、2つのロール、および1つのロールに対するいくつかのクレームをデータベースにシードするための迅速で汚いソリューションです。これは、アプリケーションの承認を管理するためのクレームアプローチを学習するためのテストアプリとして行いました。私の完全なソリューションは、各テナントが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 = "[email protected]";
            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 = "[email protected]";
            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クラスのConfirgureServicesメソッドに「ポリシー」を登録する必要がありました。これにより、クレームを1つまたは複数のポリシーにマッピングできます。

 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>();
    }

ビュー:私の使用例では、割り当てられている役割に関連付けられた「役割を追加できます」という主張を持たないユーザーから「役割の追加」ボタンを制限したいと思いました。ビューコードの残りの部分は関係ありません。私が遭遇した問題は、クレーム名を2番目のパラメーターとして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」に割り当てられたユーザー「[email protected]」があります。ロールには、任意の数のクレームを含めることができます。インジェクタブルIAuthorizationServiceAuthorizationServiceを介してビューでチェックしたのと同じ「ロールを追加できます」というクレームを持つポリシーを作成しました。ユーザーにこのクレームがロールに割り当てられていない場合、trueまたはfalseを返すポリシーチェックでは、ロールを追加するためのボタンは表示されません。これと同じポリシーチェックロジックは、新しい.netコアDIミドルウェアのおかげで、DIを介してコントローラーまたはその他のリソースに追加できます。この演習全体を通して、ビジネスロジックチェックなどを活用できるIdentity3の力を学びました。かなり甘いものですが、そこにいる作家は、私たちが肉に早く到達するのを助けるためにもっと多くの例を本当に必要としています。とにかく、これが同様のソリューションを探している将来の開発者に役立つことを願っています。

8
JReam

問題が見つかりました。ビューでクレーム「名前」とポリシー名を参照しました...

間違いを説明し、私が何をしているのかを示すために、上記のメモを追加します。 4.5を超える改善された認証ソリューションを提供してくれたBenとASP.Netのおかげで、非常に強力なものになりました。

3
JReam