Я хотел иметь условный доступ к определенному контроллеру, если пользователь принадлежит определенной роли.Этот пользователь не может получить доступ ни к чему другому.Если пользователь не из этой конкретной роли, он переходит на обычный сайт.
У меня есть два фильтра действий для этого:
CarParkAuthenticationAttribute
:
public class CarParkAuthenticationAttribute : FilterAttribute, IAuthenticationFilter
{
public void OnAuthentication(AuthenticationContext filterContext)
{
var currentUser = ParseUserNameFromOkta(filterContext.HttpContext.User.Identity.Name);
if (filterContext.HttpContext.Session[Constants.SessionVariableCurrentUser] == null)
{
var usersManager = new UsersManager();
var userCarParkTask = Task.Run(() => usersManager.FindIntranetUser(currentUser));
var userCarPark = userCarParkTask.WaitAndUnwrapException();
if (userCarPark != null)
{
var roleTask = Task.Run(() => usersManager.GetRoleByUserId(userCarPark.IntranetUserId));
var roles = roleTask.WaitAndUnwrapException();
var carParkUser = new CarParkUser(userCarPark.EmployeeName, userCarPark, roles);
filterContext.HttpContext.User = carParkUser;
filterContext.HttpContext.Session[Constants.SessionVariableCurrentUser] = carParkUser;
filterContext.HttpContext.Session[Constants.SessionVariableCurrentUserId] = carParkUser.Detail.IntranetUserId;
}
else
{
SystemLogger.Info("InternetCarParkUser was NOT found against: " + currentUser);
filterContext.HttpContext.Response.Redirect("~/Views/Error/AccessDenied");
filterContext.HttpContext.Response.End();
}
}
else // Already signed in
{
if (filterContext.HttpContext.Session[Constants.SessionVariableCurrentUser] is CarParkUser user)
{
filterContext.HttpContext.User = user;
filterContext.HttpContext.Session[Constants.SessionVariableCurrentUserId] = ((CarParkUser)filterContext.HttpContext.User).Detail.IntranetUserId;
}
else
{
filterContext.HttpContext.Response.Redirect("~/Views/Error/AccessDenied");
filterContext.HttpContext.Response.End();
}
}
}
public void OnAuthenticationChallenge(AuthenticationChallengeContext filterContext)
{
#region Valid User Check
var user = filterContext.HttpContext.User;
if ((CarParkUser)user == null || !user.Identity.IsAuthenticated)
{
filterContext.Result = new HttpUnauthorizedResult();
return;
}
#endregion
#region Confirm current user is on the list
var isTargetRole = user.IsInRole("Mawgif");
#endregion
if (isTargetRole)
{
#region Confirming target controller/action
var helper = new UrlHelper(filterContext.RequestContext);
var url = helper.Action("CarParkRequest", "Mawgif");
filterContext.Result = new RedirectResult(url);
}
}
}
CarParkAuthorizationAttribute
:
public class CarParkAuthorizationAttribute : FilterAttribute, IAuthorizationFilter
{
private static readonly ILog SystemLogger = LogManager.GetLogger("OnAuthorization");
public void OnAuthorization(AuthorizationContext filterContext)
{
if (filterContext == null)
{
SystemLogger.Error($"{nameof(filterContext)} was not found");
throw new ArgumentNullException(nameof(filterContext));
}
if (!(filterContext.HttpContext.User is CarParkUser currentUser))
{
SystemLogger.Error($"{nameof(currentUser)} was not found or is not {nameof(CarParkUser)}");
throw new ArgumentNullException(nameof(currentUser));
}
var controllerName = GetControllerName();
var actionName = GetActionName();
var isUserAllowed = currentUser.Roles != null && currentUser.Roles.Any(businessUserRole =>
businessUserRole.AllowedLocations.Any(w =>
w.ControllerName == controllerName && w.ActionName == actionName));
if (isUserAllowed) return;
SystemLogger.Warn($"Access Error: User {currentUser.Id} was not allowed to access {controllerName}/{actionName}");
var resultView = new ViewResult
{
ViewName = "~/Views/Error/AccessDenied.cshtml",
TempData =
{
["controllerName"] = controllerName,
["actionName"] = actionName,
["currentUser"] = currentUser.Detail.UserName
}
};
filterContext.Result = resultView;
}
private static string GetControllerName()
{
var routeValues = HttpContext.Current.Request.RequestContext.RouteData.Values;
if (routeValues.ContainsKey("controller"))
return (string)routeValues["controller"];
return string.Empty;
}
private static string GetActionName()
{
var routeValues = HttpContext.Current.Request.RequestContext.RouteData.Values;
if (routeValues.ContainsKey("action"))
return (string)routeValues["action"];
return string.Empty;
}
}
Оба этих фильтра установлены на базовом контроллере:
[CarParkAuthentication]
[CarParkAuthorization]
public class AsyncControllerBase : AsyncController { }
Мой контроль доступа основан на имени контроллера / действия.База данных имеет настройку отображения следующим образом:
![DB Design](https://i.stack.imgur.com/24ndS.png)
CarParkUser
:
public class CarParkUser : IPrincipal
{
public CarParkUser(string userName, BDO.IntranetUserCarPark userDetail, IList<BDO.ParkingUserRole> roles)
{
Identity = new GenericIdentity(userName);
Detail = userDetail;
Roles = roles;
}
public IIdentity Identity { get; }
public int Id => Detail.IntranetUserId;
public BDO.IntranetUserCarPark Detail { get; }
public IList<BDO.ParkingUserRole> Roles { get; }
public bool IsInRole(string role) => Roles != null && Roles.Any(where => where.RoleName == role);
}
Итак, с этой настройкой яУ меня ошибка ERR_TOO_MANY_REDIRECTS
.Мой желаемый результат был:
- Все пользователи НЕ из роли "Mawgif" имеют обычный доступ ко всему сайту
- Пользователи роли Mawgif имеют доступ только к контроллеру Mawgif и его действиям плюс одно действие от другого контроллера.Эти действия уже определены в БД и доступны из пользовательского объекта:
![locations](https://i.stack.imgur.com/Nu6jP.png)
Я чувствую, что сделал это в меру своих знаний.Я также чувствую мое ограниченное понимание IAuthenticationFilter
здесь.Любые указатели / помощь будут высоко оценены.