Комбинация OnAuthentication, OnAuthenticationChallenge и OnAuthorization приводит к ERR_TOO_MANY_REDIRECTS - PullRequest
0 голосов
/ 18 февраля 2019

Я хотел иметь условный доступ к определенному контроллеру, если пользователь принадлежит определенной роли.Этот пользователь не может получить доступ ни к чему другому.Если пользователь не из этой конкретной роли, он переходит на обычный сайт.

У меня есть два фильтра действий для этого:

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

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

Я чувствую, что сделал это в меру своих знаний.Я также чувствую мое ограниченное понимание IAuthenticationFilter здесь.Любые указатели / помощь будут высоко оценены.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...