У меня есть метод контроллера с именем UserSignIn , который используется для аутентификации пользователя. Параметр «Кандидат» - это модель, которая содержит поля, включая адрес электронной почты и пароль контакта.
Модель также содержит поля «AgencyID» и «ContactID». Они используются для того, чтобы я знал, к какой базе данных подключаться (AgencyID) и какую контактную запись получить (ContactID). Пользователь, входящий в систему, является контактом в агентстве.
[HttpPost()]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> UserSignIn(Candidate can)
{
bool is_err = false;
string err = string.Empty;
Candidate c_signed_in = new Candidate();
// check data
if (string.IsNullOrEmpty(can.Email))
{
is_err = true;
err += "<li>Missing email address.</li>";
}
if (string.IsNullOrEmpty(can.AccountPassword))
{
is_err = true;
err += "<li>Missing password.</li>";
}
// get candidate
if (ModelState.IsValid && !is_err)
{
c_signed_in = await Repository.GetCandidate(can.AgencyID, 0, can.Email.ToLower(), can.AccountPassword, hostingEnv.WebRootPath);
if (c_signed_in.ContactID == 0)
{
is_err = true;
err += "<li>No account found. Check your credentials.</li>";
}
}
// check model state
if (!ModelState.IsValid || is_err)
{
Candidate c_current = await Repository.GetBlankCandidate(can, false);
c_current.IsModeSignIn = true;
if (is_err)
c_current.ErrsSignIn = "<ul class=\"text-danger\">" + err + "</ul>";
return View("Agency", c_current);
}
// create claims
var claims = new List<Claim>
{
//new Claim(ClaimTypes.Name, c_signed_in.FirstName + gFunc.SPACE + c_signed_in.FamilyName),
new Claim(ClaimTypes.Sid, c_signed_in.ContactID.ToString()),
new Claim(ClaimTypes.Email, c_signed_in.Email)
};
// create identity
var identity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme); // cookie or local
// create principal
ClaimsPrincipal principal = new ClaimsPrincipal(new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme));
// sign-in
await HttpContext.SignInAsync(scheme: CookieAuthenticationDefaults.AuthenticationScheme, principal: principal);
// add to log
gFunc.AddLogEntry("SignIn Candidate: " + c_signed_in.FirstName + gFunc.SPACE + c_signed_in.FamilyName + " - " + c_signed_in.Email);
// fini
return RedirectToAction("Profile", new { agencyID = c_signed_in.AgencyID, contactID = c_signed_in.ContactID });
}
В случае успеха этот метод перенаправляет на метод с именем «Профиль», который отображает профиль пользователя.
[HttpGet]
[Authorize]
public async Task<ActionResult> Profile(int agencyID, int contactID)
{
Candidate can = await Repository.GetCandidate(agencyID, contactID, string.Empty, string.Empty, hostingEnv.WebRootPath);
if (can.ContactID == 0)
{
int id = agencyID;
return RedirectToAction("Agency", new { agencyID = id });
}
return View("Profile", can);
}
Мой URL сейчас "/ Главная / Профиль? AgencyID = 5809 & contactID = 19492
Однако теперь я могу просто изменить contactID в URL, и теперь я нахожусь в профиле другого пользователя без авторизации.
Как мне избежать этого? Очевидно, что я не могу включить пароль в качестве параметра в метод Profile , потому что он просто будет виден в URL. Какой подход я должен выбрать?
ОБНОВЛЕНИЕ - РЕШЕНО
Спасибо всем за ваши комментарии. Ответ Камило Теревинто решил мою проблему.
Я добавил необходимую информацию к утверждениям в методе UserSignIn и удалил параметры в методе Profile , где я могу получить необходимую информацию от активного пользователя. Теперь я могу гарантировать, что только авторизованный пользователь сможет получить доступ к методу контроллера «Профиль».
Единственное, что я должен был изменить, - это прямой международный отряд. Моему компилятору это не понравилось, поэтому я просто изменил его на использование синтаксического разбора:
int agency_id = int.Parse(User.FindFirst(ClaimTypes.NameIdentifier).Value);
int contact_id = int.Parse(User.FindFirst(ClaimTypes.Sid).Value);