ASP.NET Core MVC : developed role-based authorization

As I mentioned in the title, I am developing a program on the ASP.NET Core MVC platform. I use IdentityUser and IdentityRole when authorizing in my project.

As you know, when authorizing in this type of authorization, authorization is assigned to the action by opening tags like [Authorize(Roles = "Admin")] on the actions.

But I develop this process further and I have a table with RoleId (string), ControllerName (string), MethodName (string) and State (bool) columns that holds the action methods that the roles are authorized for.

While the program is debugging, it will review this table and according to the id of the role to which the user is connected, it will determine which of the actions in the controller from this table is authorized to access and accordingly redirect it to the AccessDenied page or enter the page.

I would be happy if someone can help me with this. Thanks in advance, good forums.

I created two classes AuthorizationService and AuthorizationMiddleware and placed the necessary code in these classes. I injected these classes into the program in the program.cs file, but I get errors.

------------------------Edit---------------------

    public class CustomAuthorizeAttribute : Attribute, IAuthorizationFilter
    {
        QlabContext _dbContext = new QlabContext();
        private readonly RoleManager<IdentityRole> _roleManager;
        private readonly UserManager<IdentityUser> _userManager;

        public CustomAuthorizeAttribute(RoleManager<IdentityRole> roleManager, UserManager<IdentityUser> userManager)
        {
            _roleManager = roleManager;
            _userManager = userManager;
        }

        public async void OnAuthorization(AuthorizationFilterContext context)
        {
            string request_controller = context.HttpContext.GetRouteData().Values["controller"].ToString();
            string request_method = context.HttpContext.GetRouteData().Values["Action"].ToString();
            bool state = false; //Initial a flag to indicate pass authorize or not

            var roleMethod = _dbContext.AspNetRoleMethods.Where(w => w.ControllerName == request_controller && w.MethodName == request_method).ToList();
            var userName = context.HttpContext.User.Identity.Name;


            if (context.HttpContext.User.Identity.IsAuthenticated)
            {
                // Giriş yapmış kullanıcının kimliğini alın
                var user = await getUserByName(userName);

                // Kullanıcının rolünü alın
                var userRoles = await getRoleList(user);

                foreach (var roles in userRoles)
                {
                    foreach (var item in roleMethod)
                    {
                        string roleName = getRoleNameById(item.RoleId);

                        if (roles == roleName && request_controller == item.ControllerName && request_method == item.MethodName)
                        {
                            state = item.State;
                            break;
                        }
                    }
                }

                if (state) //if ture ,just continue, pass authorize
                {
                    return;
                }
                else       //if false ,return a 401 result.
                {
                    context.Result = new UnauthorizedResult();
                    context.HttpContext.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
                    return;
                }
            }
            else
            {
                context.Result = new JsonResult(new { message = "Kullanıcı Doğrulanamadı" }) { StatusCode = StatusCodes.Status403Forbidden };
                return;
            }
        }

        public async Task<IList<string>> getRoleList(IdentityUser user)
        {
            return await _userManager.GetRolesAsync(user);
        }

        public string getRoleNameById(string roleId)
        {
            var role = _roleManager.Roles.Where(w => w.Id == roleId).FirstOrDefault();
            return role.Name;
        }

        public async Task<IdentityUser> getUserByName(string userName)
        {
            return await _userManager.FindByNameAsync(userName);
        }
    }

I updated the structure like this. My only problem now is in case the user logs in without authorization;

  else //if false ,return a 401 result.
  {
      context.Result = new UnauthorizedResult();
      context.HttpContext.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
      return;
  }

In the above condition, I need to redirect to the AccessDenied page that I defined in program.cs. Thanks in advance.

Upvotes: 0

Views: 202

Answers (1)

Qiang Fu
Qiang Fu

Reputation: 8861

You could make a CustomAuthorizeAttribute and use SqlReader to achieve this. Try following:
A table "roleSettings" in Databse "UserAuth3"
enter image description here

CustomAuthorizeAttribute.cs

    public class CustomAuthorizeAttribute : Attribute, IAuthorizationFilter
    {
        public void OnAuthorization(AuthorizationFilterContext context)
        {
            //Get role,controller,method from request context
            var userRole = context.HttpContext.User.FindFirstValue(ClaimTypes.Role);
            string request_controller = context.HttpContext.GetRouteData().Values["controller"].ToString();
            string request_method = context.HttpContext.GetRouteData().Values["Action"].ToString();
            
            bool state = false; //Initial a flag to indicate pass authorize or not


            //use Sqlconnection to read the Table "UserAuth3"
            string connectionString = "Server=192.168.2.68;Database=UserAuth3;User Id=sa;Password=xxxxxx;";
            using (SqlConnection connection = new SqlConnection(connectionString))
            {
                connection.Open();

                string sql = "SELECT * FROM roleSettings";   //read table "roleSettings"
                using (SqlCommand command = new SqlCommand(sql, connection))
                {
                    using (SqlDataReader reader = command.ExecuteReader())
                    {
                        while (reader.Read())  //read the table line by line, reader.GetString(1) means second row.
                        {
                            if (reader.GetString(1) == userRole && reader.GetString(2) == request_controller && reader.GetString(3) == request_method) 
                            {
                                state = reader.GetBoolean(4);  //when find the same role/controller/method line, set the state flag.
                                break;
                            }                          
                        }
                    }
                }

                connection.Close();
            }

            if (state) //if ture ,just continue, pass authorize
            {
                return; 
            }
            else       //if false ,return a 401 result.
            {
                context.Result = new JsonResult(new { message = "Access Denied" }) { StatusCode = StatusCodes.Status401Unauthorized };
                return;
            }
        }
    }

Add the Attribute at top of Controller

    [CustomAuthorize]
    public class HomeController : Controller
    {
       ...

Register a user and assign an "Admin" role.

                var result = await _userManager.CreateAsync(user, Input.Password);

                await _roleManager.CreateAsync(new IdentityRole("Admin"));
                await _userManager.AddToRoleAsync(user, "Admin");

Test
enter image description here

-------------------------Update of rolemangager usage-----------
When using the rolemanager,you will need to add IdentityRole to service.
"AddDefaultIdentity" pattern

builder.Services.AddDefaultIdentity<IdentityUser>().AddRoles<IdentityRole>()
    .AddEntityFrameworkStores<ApplicationDbContext>();

"AddIdentity" patern

builder.Services.AddIdentity<IdentityUser,IdentityRole>()
    .AddEntityFrameworkStores<ApplicationDbContext>();

Usage reference :https://procodeguide.com/programming/aspnet-core-identity-roles-authorization/

Upvotes: -1

Related Questions