Мой проект веб-приложения 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);
}