[英]MVC 5 - set session variable at login
我正在構建MVC 5應用程序,並且遇到以下問題:用戶登錄后,如果用戶與我達成協議,我想向用戶顯示菜單項。
我想在用戶登錄時設置會話變量,例如:
Session["HasAgreement"] = Agreement.HasAgreement(userId);
然后在構建菜單的_Layout.cshtml文件中執行以下操作:
@if (Session["HasAgreement"] == "True")
{
<li>@Html.ActionLink("Agreement", "Agreement", "Home")</li>
}
我的問題出在AccountController上,在其中我已將邏輯添加到標准Login Action中:
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 userId = User.Identity.GetUserId();
Session["HasAgreement"] = Agreement.HasAgreement(userId);
return RedirectToLocal(returnUrl);
case SignInStatus.LockedOut:
return View("Lockout");
case SignInStatus.RequiresVerification:
return RedirectToAction("SendCode", new { ReturnUrl = returnUrl, RememberMe = model.RememberMe });
case SignInStatus.Failure:
default:
ModelState.AddModelError("", "Invalid login attempt.");
return View(model);
}
}
這是標准的MVC 5登錄-除了在“ case SignInStatus.Success:”之后添加兩行外,我嘗試獲取userId,然后設置Session變量。
我的問題是,此時在thime中,用戶尚未通過身份驗證(我認為是在上面的SignInManager中發生的)。
用戶登錄后如何設置會話變量?
在您執行下一個操作之前,不會設置新的會話。 嘗試將結果用於重定向以外的其他問題時,這是一個常見問題。 最好的措施是使用結果重定向到另一個操作,然后您就可以在其中訪問會話。
假設您的用戶登錄時轉到“儀表板”,則可能類似於:
SignInStatus。成功案例:
case SignInStatus.Success:
return RedirectToAction("Dashboard");
如果需要返回許多動作的功能,則可以返回動作名稱而不是url,只需執行RedirectToAction(returnAction)
。 顯然,如果還需要指定一個控制器,則也需要發布一個returnController
。
儀表板動作:
[Authorize]
public ActionResult Dashboard() {
var userId = User.Identity.GetUserId();
Session["HasAgreement"] = Agreement.HasAgreement(userId);
return View();
}
您的問題不是更新會話變量時,而是布局頁面獲得會話的哪個版本。
會話不是在視圖之間傳遞數據的最佳選擇。 嘗試使用ViewBag
(盡管您應該始終盡可能嘗試使用ViewModel!)(並且可以將會話AS WELL用於下一頁加載)
我不確定您的Agreement
對象來自何處,但是您可以訪問“ View
中的“ User
屬性,因此可以執行以下操作:
_Layout.cshtml
@if (Agreement.HasAgreement(User.Identity.GetUserId()))
{
<li>@Html.ActionLink("Agreement", "Agreement", "Home")</li>
}
這也假設HasAgreement
返回一個bool
,如果沒有,則確實應該。
這可能並非在所有情況下都可行,但是我發現在Login上設置會話變量的最簡單方法是將邏輯移至RedirectToLocal()
返回的控制器動作。 在我的情況下,我為應用程序創建了一個新的登錄后入口點,稱為“ Main”,它具有自己的視圖/控制器。 登錄時,始終總是首先將用戶重定向到此處,因此可以確保設置我的會話數據。
首先,我在AccountController
更改了RedirectToLocal()
:
private ActionResult RedirectToLocal(string returnUrl)
{
if (Url.IsLocalUrl(returnUrl))
{
return Redirect(returnUrl);
}
//This is the template default
//return RedirectToAction("Index", "Home");
//This is my new entry point.
return RedirectToAction("Index", "Main"); }
在我的MainController
內部,我可以訪問User
對象並設置數據:
// GET: Main
public ActionResult Index()
{
ApplicationUser sessionuser = db.Users.Find(User.Identity.GetUserId());
Session.Add("UserName", sessionuser.UserName);
return View();
}
而且,在注銷時,我會擦除會話數據:
public ActionResult LogOff()
{
Session.RemoveAll(); //Clear all session variables
//...
}
作為選擇:
添加新的局部視圖,將其稱為Agreement
。
@model bool
@if (Model)
{
<li>@Html.ActionLink("Agreement", "Agreement", "Home")</li>
}
向您的Account
控制者添加新操作,將其稱為Agreement
public PartialViewResult Agreement(){
var userId = User.Identity.GetUserId();
bool hasAgreement = Agreement.HasAgreement(userId); // This will be your model
return PartialView("Agreement", hasAgreement);
}
並在您的布局中執行以下操作:
@Html.RenderAction("Agreement", "Account")
我有完全相同的問題,並且似乎正在使用與您(OP)相同的身份版本。 我嘗試了您做過的事情(在發現之前),並按照Sippy的建議,將其放在AccountController
RedirectToLocal
ActionResult
中(無效):
同時,我將其放在Global.Asax.cs中:
public void Profile_OnMigrateAnonymous(object sender, ProfileMigrateEventArgs args)
{
...//other code (or not) on migrate anonymous user to authenticated
Session["HasAgreement"] = Agreement.HasAgreement(userId);
}
我還在Global.asax.cs中創建了此空缺(捕獲了過期的會話,但仍已登錄):
void Session_Start(object sender, EventArgs e)
{
Session["HasAgreement"] = Agreement.HasAgreement(userId);
}
它可以正常工作,如果會話過期,它也會更新。 但是,這樣做的缺點之一是,當用戶注銷(通過身份)時,會話變量將不會更新。 但是,我也嘗試將我的客戶端擴展放在AuthenticationManager.SignOut();
之后的LogOff
ActionResult
AuthenticationManager.SignOut();
而且不起作用。
我也需要在注銷后更新會話變量,所以這不是我的最終解決方案,但這對您來說足夠好了嗎?
如果找到更好的方法,我會回來更新此方法,但是現在,它已經足夠好了,並列在我的TODO
列表中。
更新:
為了捕獲用戶的注銷事件,我使用了Sippy的想法,並將AccountController
LogOff
ActionResult
更改為此:
//
// POST: /Account/LogOff
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult LogOff()
{
AuthenticationManager.SignOut();
return RedirectToAction("SetSessionVariables", "Account");
}
[AllowAnonymous]
public ActionResult SetSessionVariables()
{
Session["HasAgreement"] = Agreement.HasAgreement(userId);
return RedirectToAction("Index", "Home");
}
我認為這涵蓋了所有登錄/注銷/會話方案。 我可能會看到是否可以將對LogOff所做的工作整合到登錄成功重定向中(更多的是查看用戶何時實際上已“經過身份驗證”)。
您可以使用用戶聲明來擴展身份數據。
此處的示例實現: 如何擴展User.Identity的可用屬性
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.