Reputation: 11
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
Reputation: 8861
You could make a CustomAuthorizeAttribute and use SqlReader to achieve this. Try following:
A table "roleSettings" in Databse "UserAuth3"
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");
-------------------------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