我有一个称为 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现在为“ / Home / Profile?agencyID = 5809&contactID = 19492
但是,我现在只需更改URL中的contactID,现在我就在未经授权的情况下位于另一个用户的个人资料中。
如何避免这种情况?显然,我不能在 Profile 方法中将密码作为参数包含进来,因为它只是在URL中可见。我应该采取什么方法?
更新-已解决
感谢大家的评论。 Camilo Terevinto的答案解决了我的问题。
我在 UserSignIn 方法中的声明中添加了所需的信息,并在 Profile 方法中删除了参数,以便从活动目录中检索所需的信息用户。现在,我可以确保只有授权用户才能使用“配置文件”控制器方法。
我唯一需要更改的是直接int cast。我的编译器不喜欢它,所以我只是将其更改为使用解析:
int agency_id = int.Parse(User.FindFirst(ClaimTypes.NameIdentifier).Value);
int contact_id = int.Parse(User.FindFirst(ClaimTypes.Sid).Value);
答案 0 :(得分:4)
您可以在声明中添加 agencyID 和 contactID :
new Claim(ClaimTypes.Sid, c_signed_in.ContactID.ToString()),
new Claim(ClaimTypes.Email, c_signed_in.Email),
new Claim(ClaimTypes.NameIdentifier,c_signed_in.agencyID.ToString())
在控制器中,您可以从记录的用户数据中获取它:
[HttpGet]
[Authorize]
public async Task<ActionResult> Profile()
{
int agencyID = (int)User.FindFirst(ClaimTypes.NameIdentifier).Value
int contactID = (int) User.FindFirst(ClaimTypes.Sid).Value
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);
}