Как лучше реализовать второй уровень входа в проект ASP.NET MVC - PullRequest
2 голосов
/ 11 мая 2019

Мой проект веб-приложения ASP.NET MVC требует наличия логина пользователя, а затем, после успешного входа в систему, пользователь должен выбрать одну из клиник, членом которой он является. Я добавил пользовательский атрибут в FilterConfig, чтобы определить, выбрана ли у текущего пользователя клиника. Я сохраняю идентификатор выбранной клиники в сеансе, поскольку все приложения, операции CRUD, данные, изображения и т. Д. Будут зависеть от того, какую клинику выбрал пользователь.

Кроме того, если пользователь является членом только одной клиники, выбор не требуется. Пользователь должен / всегда будет участником хотя бы одной клиники.

Вот как я это реализовал.
У меня вопрос, если бы я реализовал это эффективно, с точки зрения производительности.
Мои опасения касаются хранения идентификатора клиники в сеансе и поездок в базу данных при проверке списка клиник пользователя.
Есть ли лучший способ сделать это?

Модель моего приложения для пользователя:

public class ApplicationUser : IdentityUser
{
    // parts redacted

    public ICollection<Clinic> Clinics { get; set; }
    // parts redacted
}

Модель моей клиники:

public class Clinic
{
    // parts redacted

    public ICollection<ApplicationUser> Users { get; set; } 
}

Мой пользовательский атрибут:

public class SessionClinicAttribute : ActionFilterAttribute
{
    private bool _filter;

    public SessionClinicAttribute(bool filter = true)
    {
        _filter = filter;
    }

    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        HttpContext ctx = HttpContext.Current;

        if (_filter && !ctx.User.Identity.IsAuthenticated) {
            filterContext.Result = new RedirectResult("~/Account/Login?returnUrl=" +
            filterContext.HttpContext.Server.UrlEncode(filterContext.HttpContext.Request.RawUrl));
            return;
        }

        if (_filter && ctx.Session["ClinicId"] == null)
        {
                filterContext.Result = new RedirectResult("~/Account/ClinicLogin?returnUrl=" +
                filterContext.HttpContext.Server.UrlEncode(filterContext.HttpContext.Request.RawUrl));

            return;
        }

        base.OnActionExecuting(filterContext);
    }
}

Части моего AccountController:

    [HttpPost]
    [AllowAnonymous]
    [SessionClinic (false)]
    [ValidateAntiForgeryToken]
    public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
    {
        if (!ModelState.IsValid)
        {
            return View(model);
        }

        var result = await SignInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, shouldLockout: false);
        switch (result)
        {
            case SignInStatus.Success:
                var user = _context.Users.Include(u => u.Clinics).Single(u => u.UserName == model.Email);
                if (user.Clinics.Count > 1)
                {
                    Session["ClinicId"] = null;
                    return RedirectToAction("ClinicLogin", new {ReturnUrl = returnUrl});
                }

                Session["ClinicId"] = user.Clinics.ToList()[0].Id;
                return RedirectToLocal(returnUrl);
            // parts redacted
            default:
                ModelState.AddModelError("", "Invalid login attempt.");
                return View(model);
        }
    }

    [HttpPost]
    [SessionClinic(false)]
    public ActionResult ClinicLogin(long clinicId, string returnUrl)
    {
        var userId = User.Identity.GetUserId();
        var user = _context.Users.Include(u => u.Clinics).Single(u => u.Id == userId);
        if (user.Clinics.Any(c => c.Id == clinicId))
            Session["ClinicId"] = clinicId;
        else
            return View("Error");

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