Search code examples
c#asp.net-coreauthorizationmicroservicesroles

How can I get a users role from DB to populate the AuthorizeAttribute


I have a .netcore mvc app where I'm having Roles in CustomRoles class :

public class CustomRoles
    {
       ///<Summary>Manager role</Summary>
       public const string Manager = "Manager";

       ///<Summary>Publisher role </Summary>
       public const string Publisher = "Publisher";
    }

In my controller, I'm setting Authorize on the endpoint :

    /// <summary>
    /// ASYNC Version: Get a List of Journals based on a Week Id
    /// </summary>
    /// <param name="weekId">Database unique Week ID</param>       
    /// <response code="204">No Content</response>
    /// <response code="400">Bad Request</response> 
    /// <returns></returns>
    [Authorize(Roles = CustomRoles.Manager +","+ CustomRoles.Publisher)]
    [HttpGet("GetPartnerJounalsByIdAsync/")]
    [ProducesResponseType(200, Type = typeof(JounalsPartnerGetResponse))]
    [ProducesResponseType(204)]
    [ProducesResponseType(400)]
    public async Task<ActionResult> GetPartnerJournalsByIdAsync([Required]int weekId)
    {
        //get from db
    }

I want to Populate Roles from the Database instead of hard-coding them in the class, so I can achieve this :

[Authorize (Roles = //Roles from the database)]

Here is the solution which I created,But I'm stuck. I implemented a Role class :

 public class Role
    {
        /////<Summary>Manager role</Summary>
        public string RoleName { get; set; }
    }

and a method to get Roles from Database :

    /// <summary>
    /// Get All Roles
    /// </summary>
    /// <returns></returns>
    public async Task<List<Role>> GetRoles()
    {
        GetResponse response = new GetResponse();
        List<Role> CRoles = new List<CustomRoles>();
        response = await database.ObjectGetTypedListAsync<Role>("", "Role");
        CRoles = (List<Role>)response.StronglyTypedObject;
        return CRoles;
    }

Any ideas how I can accomplish this ?


Solution

  • For checking role based on data in database, you could implement your own IAuthorizationFilter like

    [AttributeUsage(AttributeTargets.Class)]
    public class MyAuthorize : Attribute, IAuthorizationFilter
    {
        public void OnAuthorization(AuthorizationFilterContext context)
        {
            var dbContext = context.HttpContext.RequestServices.GetRequiredService<ApplicationDbContext>();
            var roles = dbContext.Roles.ToList();
            foreach (var role in roles)
            {
                if (!context.HttpContext.User.IsInRole(role.Name))
                {
                    context.Result = new ForbidResult();
                }
            }
        }
    }
    

    And use it like:

    [MyAuthorize]
    public IActionResult About()
    {
        ViewData["Message"] = "Your application description page.";
    
        return View();
    }