{"id":22299269,"url":"https://github.com/mo-esmp/dynamicrolebasedauthorizationnetcore","last_synced_at":"2025-05-14T15:06:40.796Z","repository":{"id":39542441,"uuid":"135583035","full_name":"mo-esmp/DynamicRoleBasedAuthorizationNETCore","owner":"mo-esmp","description":"Dynamic Role-Based Access Control for ASP.NET Core MVC and Web API","archived":false,"fork":false,"pushed_at":"2024-11-04T21:56:47.000Z","size":2778,"stargazers_count":493,"open_issues_count":8,"forks_count":101,"subscribers_count":18,"default_branch":"dev","last_synced_at":"2025-05-10T11:46:45.479Z","etag":null,"topics":["asp-net-core","asp-net-core-identity","asp-net-identity","discovering-controllers","dynamic-auth","dynamic-rbac","hardcode-roles","identity","rbac","rbac-authorization","rbac-roles","role-based-access-control"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mo-esmp.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-05-31T12:49:56.000Z","updated_at":"2025-04-29T19:50:57.000Z","dependencies_parsed_at":"2024-11-02T13:27:18.329Z","dependency_job_id":"1647af57-7445-4176-8955-1effe4ce8a2d","html_url":"https://github.com/mo-esmp/DynamicRoleBasedAuthorizationNETCore","commit_stats":null,"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mo-esmp%2FDynamicRoleBasedAuthorizationNETCore","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mo-esmp%2FDynamicRoleBasedAuthorizationNETCore/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mo-esmp%2FDynamicRoleBasedAuthorizationNETCore/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mo-esmp%2FDynamicRoleBasedAuthorizationNETCore/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mo-esmp","download_url":"https://codeload.github.com/mo-esmp/DynamicRoleBasedAuthorizationNETCore/tar.gz/refs/heads/dev","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254169389,"owners_count":22026211,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["asp-net-core","asp-net-core-identity","asp-net-identity","discovering-controllers","dynamic-auth","dynamic-rbac","hardcode-roles","identity","rbac","rbac-authorization","rbac-roles","role-based-access-control"],"created_at":"2024-12-03T18:05:04.899Z","updated_at":"2025-05-14T15:06:40.774Z","avatar_url":"https://github.com/mo-esmp.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Dynamic Role-Based Authorization in ASP.NET Core MVC 3.1, 5.0, 6.0 and 7.0 [![NuGet](http://img.shields.io/nuget/v/DynamicAuthorization.Mvc.Core.svg?style=flat)](https://www.nuget.org/packages/DynamicAuthorization.Mvc.Core) \n\nYou already know how role-based authorization works in ASP.NET Core.\n\n```c#\n[Authorize(Roles = \"Administrator\")]\npublic class AdministrationController : Controller\n{\n}\n```\n\nBut what if you don't want hardcode roles on the `Authorize` attribute or create roles later and specify in which controller and action it has access without touching source code?\n\n**DynamicAuthorization** helps you authorize users without hardcoding role(s) on the  `Authorize` attribute with minimum effort. DynamicAuthorization is built at the top of ASP.NET Core Identity and uses identity mechanism for managing roles and authorizing users.\n\nInstall the _DynamicAuthorization.Mvc.Core_ [NuGet package](https://www.nuget.org/packages/DynamicAuthorization.Mvc.Core) \n```powershell\nInstall-Package DynamicAuthorization.Mvc.Core\n```\nor\n```shell\ndotnet add package DynamicAuthorization.Mvc.Core\n```\n\nThen, add `AddDynamicAuthorization()` to `IServiceCollection` in `Startup.ConfigureServices` method:\n```csharp\npublic void ConfigureServices(IServiceCollection services)\n{\n    ...\n    services\n        .AddIdentity\u003cIdentityUser, IdentityRole\u003e(options =\u003e options.SignIn.RequireConfirmedAccount = false)\n        .AddEntityFrameworkStores\u003cApplicationDbContext\u003e()\n        .AddDefaultTokenProviders();\n        \n    services\n        .AddDynamicAuthorization\u003cApplicationDbContext\u003e(options =\u003e options.DefaultAdminUser = \"UserName\")\n```\nYou can set the default admin username via `DefaultAdminUser` config to access everywhere without creating a default admin role and its access.\n\nThen install JSON or SQLSever store to save role access.\n\nTo install _DynamicAuthorization.Mvc.JsonStore_ [NuGet package](https://www.nuget.org/packages/DynamicAuthorization.Mvc.JsonStore)\n```powershell\nInstall-Package DynamicAuthorization.Mvc.JsonStore\n```\nor\n```shell\ndotnet add package DynamicAuthorization.Mvc.JsonStore\n```\n```csharp\npublic void ConfigureServices(IServiceCollection services)\n{\n        \n    services\n        .AddDynamicAuthorization\u003cApplicationDbContext\u003e(options =\u003e options.DefaultAdminUser = \"UserName\")\n        .AddJsonStore(options =\u003e options.FilePath = \"FilePath\");\n```\nRole access will be saved in a JSON file and you can specify the file path `FilePath` config.\n\nOr install SQLServer store _DynamicAuthorization.Mvc.MsSqlServerStore_ [NuGet package](https://www.nuget.org/packages/DynamicAuthorization.Mvc.MsSqlServerStore)\n```powershell\nInstall-Package DynamicAuthorization.Mvc.MsSqlServerStore\n```\nor\n```shell\ndotnet add package DynamicAuthorization.Mvc.MsSqlServerStore\n```\n```csharp\npublic void ConfigureServices(IServiceCollection services)\n{\n        \n    services\n        .AddDynamicAuthorization\u003cApplicationDbContext\u003e(options =\u003e options.DefaultAdminUser = \"UserName\")\n        .AddSqlServerStore(options =\u003e options.ConnectionString = \"ConnectionString\");\n```\n\nYou can decorate controllers and actions with `DisplayName` attribute to show the user a more meaningful name instead of controller and action name.\n```c#\n[DisplayName(\"Access Management\")]\npublic class AccessController : Controller\n{\n\n    // GET: Access\n    [DisplayName(\"Access List\")]\n    public async Task\u003cActionResult\u003e Index()\n}\n```\n\nYou can also the default UI for managing roles and assigning roles to users if you don't want to implement them by yourself.\n\nInstall the _DynamicAuthorization.Mvc.Ui_ [NuGet package](https://www.nuget.org/packages/DynamicAuthorization.Mvc.Ui)\n\n```powershell\nInstall-Package DynamicAuthorization.Mvc.Ui\n```\n\nThen `AddUi` to DynamicAuthorization registration:\n```\nservices\n        .AddDynamicAuthorization\u003cApplicationDbContext\u003e(options =\u003e options.DefaultAdminUser = \"UserName\")\n        .AddJsonStore(options =\u003e options.FilePath = \"FilePath\")\n        .AddUi();\n```\n\nUse `http://\u003cyour-app\u003e/role` url to manage roles and assign access to a role.\n\n![create project](https://raw.githubusercontent.com/mo-esmp/DynamicRoleBasedAuthorizationNETCore/dev/assets/create-role-2.jpg)\n\nUse `http://\u003cyour-app\u003e/userrole` url to assign roles to users.\n\nYou can also use a custom `TagHelper` to check whether the user has access to view content or not. create a custom tag helper that inherits from `SecureContentTagHelper`\n\n```c#\n[HtmlTargetElement(\"secure-content\")]\npublic class MySecureContentTagHelper : SecureContentTagHelper\u003cApplicationDbContext\u003e\n{\n    public MySecureContentTagHelper(\n        ApplicationDbContext dbContext,\n        DynamicAuthorizationOptions authorizationOptions,\n        IRoleAccessStore roleAccessStore\n        )\n        : base(dbContext, authorizationOptions, roleAccessStore)\n    {\n    }\n}\n```\n\nIn each view wrap a content or an anchor tag inside `secure-content` tag:\n\n```html\n\u003cul class=\"nav navbar-nav\"\u003e\n    \u003cli\u003e\u003ca asp-area=\"\" asp-controller=\"Home\" asp-action=\"Index\"\u003eHome\u003c/a\u003e\u003c/li\u003e\n    \u003cli\u003e\u003ca asp-area=\"\" asp-controller=\"Home\" asp-action=\"About\"\u003eAbout\u003c/a\u003e\u003c/li\u003e\n    \u003cli\u003e\u003ca asp-area=\"\" asp-controller=\"Home\" asp-action=\"Contact\"\u003eContact\u003c/a\u003e\u003c/li\u003e\n    \n    \u003csecure-content asp-area=\"\" asp-controller=\"Role\" asp-action=\"Index\"\u003e\n        \u003cli\u003e\u003ca asp-area=\"\" asp-controller=\"Role\" asp-action=\"Index\"\u003eRole\u003c/a\u003e\u003c/li\u003e\n    \u003c/secure-content\u003e\n    \u003csecure-content asp-area=\"\" asp-controller=\"Access\" asp-action=\"Index\"\u003e\n        \u003cli\u003e\u003ca asp-area=\"\" asp-controller=\"Access\" asp-action=\"Index\"\u003eAccess\u003c/a\u003e\u003c/li\u003e\n    \u003c/secure-content\u003e\n\u003c/ul\u003e\n```\n\nDon't forget to add your tag halper namespace to `_ViewImports.cshtml`:\n```cshtml\n@using SampleMvcWebApp\n@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers\n@addTagHelper *, SampleMvcWebApp\n```\n\nIf you extended `IdentityUser` or you changed user and role key, you should pass user and role type too. for example:\n\n```c#\npublic class ApplicationDbContext : IdentityDbContext\u003cApplicationUser\u003e { ... }\npublic class MySecureContentTagHelper : SecureContentTagHelper\u003cApplicationDbContext, ApplicationUser\u003e { ... }\n```\n\nor\n\n```c#\npublic class ApplicationDbContext : IdentityDbContext\u003cApplicationUser, ApplicationRole, int\u003e { ... }\npublic class MySecureContentTagHelper : SecureContentTagHelper\u003cApplicationDbContext, ApplicationUser, ApplicationRole, int\u003e { ... }\n```\n#\n\nIf you don't want to use the default UI, follow the below steps to discover controllers and actions and give access to the role and then assign role(s) to the user.\nThe next step is discovering controllers and actions. `IMvcControllerDiscovery` return all controllers and actions that decorated with `[Authorize]` attribute. `IMvcControllerDiscovery.GetControllers()` method returns list of  `MvcControllerInfo`:\n\n```c#\npublic class MvcControllerInfo\n{\n    public string Id =\u003e $\"{AreaName}:{Name}\";\n\n    public string Name { get; set; }\n\n    public string DisplayName { get; set; }\n\n    public string AreaName { get; set; }\n\n    public IEnumerable\u003cMvcActionInfo\u003e Actions { get; set; }\n}\n\npublic class MvcActionInfo\n{\n    public string Id =\u003e $\"{ControllerId}:{Name}\";\n\n    public string Name { get; set; }\n\n    public string DisplayName { get; set; }\n\n    public string ControllerId { get; set; }\n}\n```\n\nThe next step is creating a role to assign access to it. Use `RoleManager\u003c\u003e` to create role and `IRoleAccessStore` to store role access.\n\n```c#\nvar role = new IdentityRole { Name = \"RoleName\" };\nvar result = await _roleManager.CreateAsync(role);\n\nvar controllers = _mvcControllerDiscovery.GetControllers();\nvar roleAccess = new RoleAccess\n{\n    Controllers = controllers.First(),\n    RoleId = role.Id\n};\nawait _roleAccessStore.AddRoleAccessAsync(roleAccess);\n```\n\nThe final step is assigning a created role to a user:\n\n```c#\nvar user = await _userManager.FindByIdAsync(\"someId\");\nawait _userManager.AddToRolesAsync(user, new [] { \"RoleName\" });\n```\n\nAnd now the user only can access those controllers and actions that his roles can access.\n\nHere is an example to create a role and assign access to the role.\n```c#\npublic class RoleViewModel\n{\n    [Required]\n    [StringLength(256, ErrorMessage = \"The {0} must be at least {2} characters long.\")]\n    public string Name { get; set; }\n\n    public IEnumerable\u003cMvcControllerInfo\u003e SelectedControllers { get; set; }\n}\n\n[DisplayName(\"Role Management\")]\npublic class RoleController : Controller\n{\n    private readonly IMvcControllerDiscovery _mvcControllerDiscovery;\n    private readonly IRoleAccessStore _roleAccessStore;\n    private readonly RoleManager\u003cIdentityRole\u003e _roleManager;\n\n    public RoleController(\n        IMvcControllerDiscovery mvcControllerDiscovery,\n        IRoleAccessStore roleAccessStore,\n        RoleManager\u003cIdentityRole\u003e roleManager\n        )\n    {\n        _mvcControllerDiscovery = mvcControllerDiscovery;\n        _roleManager = roleManager;\n        _roleAccessStore = roleAccessStore;\n    }\n\n    // GET: Role/Create\n    [DisplayName(\"Create Role\")]\n    public ActionResult Create()\n    {\n        var controllers = _mvcControllerDiscovery.GetControllers();\n        ViewData[\"Controllers\"] = controllers;\n\n        return View();\n    }\n    \n    // POST: Role/Create\n    [HttpPost, ValidateAntiForgeryToken]\n    public async Task\u003cActionResult\u003e Create(RoleViewModel viewModel)\n    {\n        if (!ModelState.IsValid)\n        {\n            ViewData[\"Controllers\"] = _mvcControllerDiscovery.GetControllers();\n            return View(viewModel);\n        }\n\n        var role = new IdentityRole { Name = viewModel.Name };\n        var result = await _roleManager.CreateAsync(role);\n\n        if (!result.Succeeded)\n        {\n            foreach (var error in result.Errors)\n                ModelState.AddModelError(\"\", error.Description);\n\n            ViewData[\"Controllers\"] = _mvcControllerDiscovery.GetControllers();\n            return View(viewModel);\n        }\n\n        if (viewModel.SelectedControllers != null \u0026\u0026 viewModel.SelectedControllers.Any())\n        {\n            foreach (var controller in viewModel.SelectedControllers)\n                foreach (var action in controller.Actions)\n                    action.ControllerId = controller.Id;\n\n            var roleAccess = new RoleAccess\n            {\n                Controllers = viewModel.SelectedControllers.ToList(),\n                RoleId = role.Id\n            };\n            await _roleAccessStore.AddRoleAccessAsync(roleAccess);\n        }\n\n        return RedirectToAction(nameof(Index));\n    }\n}\n```\nCheckout samples to view full implementation.\n\n#\n\nTo implement DynamicAuthorization step by step by yourself checkout [manual branch](https://github.com/mo-esmp/DynamicRoleBasedAuthorizationNETCore/tree/manual).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmo-esmp%2Fdynamicrolebasedauthorizationnetcore","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmo-esmp%2Fdynamicrolebasedauthorizationnetcore","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmo-esmp%2Fdynamicrolebasedauthorizationnetcore/lists"}