2014-05-16 47 views
0

所以我成立了我的MVC應用程序自定義登錄這似乎工作...定製登錄與MVC搞亂與登錄局部視圖

public ActionResult Login() 
{ 
    return View(); 
} 
[HttpPost] 
public ActionResult Login(User model, string returnUrl) 
{ 
    if (ModelState.IsValid) 
    { 
     if (model.Login()) 
     { 
      FormsAuthentication.SetAuthCookie(model.Username, true); 
      if (Url.IsLocalUrl(returnUrl) && returnUrl.Length > 1 && returnUrl.StartsWith("/") && !returnUrl.StartsWith("//") && !returnUrl.StartsWith("/\\")) 
      { 
       return Redirect(returnUrl); 
      } 
      else 
      { 
       return RedirectToAction("Index", "Home"); 
      } 
     } 
     else 
     { 
      ModelState.AddModelError("", "Invalid email address or password."); 
     } 
    } 

    // If execution got this far, something failed, redisplay form 
    return View(model); 
} 

public class User 
{ 
    public bool Login() 
    { 
     var user = db.Users.FirstOrDefault(u => u.EmailAddress == EmailAddress); 

     if (user == null) 
     { 
      throw new ValidationException("User not found."); 
     } 
     else 
     { 
      // validates whether or not the password on the user record 
      // that was retrieved by the query matches the password entered at login 
      return Hashing.ValidatePassword(Password, user.Password); 
     } 
    } 
} 

遺憾的是,它與之間的一些衝突默認_LoginPartial.cshtml視圖(看上去像下圖):

@model LoganMVC.Models.User 
@if (Request.IsAuthenticated) { 
    <text> 
     Hello, @Html.ActionLink(User.Identity.Name, "Manage", "Account", new { User.Identity.Name })! 
     @using (Html.BeginForm("LogOff", "Account", FormMethod.Post, new { id = "logoutForm" })) { 
      @Html.AntiForgeryToken() 
      <a href="javascript:document.getElementById('logoutForm').submit()">Log off</a> 
     } 
    </text> 
} else { 
    <ul> 
     <li>@Html.ActionLink("Register", "Register", "Account", routeValues: null, htmlAttributes: new { id = "registerLink" })</li> 
     <li>@Html.ActionLink("Log in", "Login", "Account", routeValues: null, htmlAttributes: new { id = "loginLink" })</li> 
    </ul> 
} 

的ArgumentNullException突出這條線......

您好,@ Html.ActionLink(User.Identity.Name,「Manage」,「Account」,new {User.Identity.Name})!

說...

值不能爲空。

很顯然,這不能爲空或空值User.Identity.Name,但有什麼不清楚的是,爲什麼IsAuthenticated是真正開始。這是表單身份驗證,就軟件而言(因爲我殺死了調試服務器,關閉瞭解決方案並再次開始調試),應用程序從未運行過。

回答

1

好吧我一直在抨擊我的頭對抗各種硬表面,試圖讓這一個想出來,最終做到了。

看錯誤後我最初得到:

值不能爲空。

再後來

型 'System.Web.Security.FormsIdentity' 的身份提供標記IsAuthenticated = true,但沒有name的值。默認情況下,防僞系統要求所有經過身份驗證的身份都有唯一的名稱。如果無法爲此標識提供唯一名稱,請考慮將靜態屬性AntiForgeryConfig.AdditionalDataProvider設置爲可爲當前用戶提供某種形式的唯一標識符的類型實例。

是相當簡單的修復。

首先,我最初設置了我的登錄cookie以堅持。這意味着它在瀏覽器關閉時不會被刪除,也不會過期。雖然這不會導致Value cannot be null or empty錯誤,但這是因爲該網站發現它並假設用戶已通過身份驗證。

FIX
爲了解決這個問題,我簡單地清除餅乾從我的瀏覽器中設置cookie的堅持爲false。這讓我更專注於實際問題。

值不能爲null或空

這個問題實際上並不複雜,因爲我以爲。當我開始服用的東西仔細一看,我注意到,有下面的代碼中的錯誤:

[HttpPost] 
public ActionResult Login(User model, string returnUrl) 
{ 
    if (ModelState.IsValid) 
    { 
     if (model.Login()) 
     { 
      FormsAuthentication.SetAuthCookie(model.Username, true); 
      if (Url.IsLocalUrl(returnUrl) && returnUrl.Length > 1 && returnUrl.StartsWith("/") && !returnUrl.StartsWith("//") && !returnUrl.StartsWith("/\\")) 
      { 
       return Redirect(returnUrl); 
      } 
      else 
      { 
       return RedirectToAction("Index", "Home"); 
      } 
     } 
     else 
     { 
      ModelState.AddModelError("", "Invalid email address or password."); 
     } 
    } 

    // If execution got this far, something failed, redisplay form 
    return View(model); 
} 

這個帖子捕獲從形式我的用戶模型的實例(也就是登錄表單,所以只有EmailAddress的幷包含密碼值)。它還使用此模型的用戶名值(該值爲空)來設置身份驗證Cookie。

我將.Login()方法更改爲一個函數,該函數在找到電子郵件地址並且存儲的散列值與輸入的用於登錄的密碼的散列值相同時返回用戶。

的代碼,因此,更改爲以下(這只是變化的關鍵點)

// Account.Login Post 
if (ModelState.IsValid) 
{ 
    var user = model.Login(model.EmailAddress); 
    if (user == null) 
    { 
     ModelState.AddModelError("", "Invalid email address or password."); 
    } 

    FormsAuthentication.SetAuthCookie(user.Username, true); 
    // create session variables n such 
} 

// User.Login 
public User Login(string EmailAddress 
{ 
    var user = dbContext.Users.FirstOrDefault(u => u.EmailAddress == Email); 

    if (user == null) 
     throw new Exception("User not found."); 

    if (Hashing.ValidatePassword(Password, user.Password)) 
     return user; 

    return null; // if we got here, something went wrong 
} 

一旦我已經解決了這個問題,後來我得到了另一個問題。一些與防僞系統有關的問題。

雖然不是一個解決方案,我管理的解決辦法,並從我的_LoginPartial查看註釋掉以下行:

@Html.AntiForgeryToken() 

我對安全的關注,但我想,在一個基本的asp.net網站與窗體身份驗證一個哈希和鹽漬密碼已經足夠多年,所以我不應該在這裏有任何問題。

0

你可能會錯過一些東西。在你的控制器Account你有一個動作:

public ActionResult Manage(string name) // I presume name 
{ 
    .... 
} 

那麼你的行應該是:

Hello, @Html.ActionLink(User.Identity.Name, "Manage", "Account", new { name=User.Identity.Name })! 

匿名對象,它是routeValues 這是一個包含路由參數N對象。通過檢查對象的屬性通過反射來檢索參數。該對象通常使用對象初始化器語法創建(定義取自MSDN)並且它應該格式化良好。

我希望它能解決問題,否則你必須檢查User.Identity是否與null不同。 我也注意到其他的財產以後在這行:

var user = db.Users.FirstOrDefault(u => u.EmailAddress == EmailAddress); 

其中來自==EmailAddress? 您應該爲您提供一個參數Login方法來替換您的第二個EmailAddress

public bool Login(string emailAddress) 
    { 
    var user = db.Users.FirstOrDefault(u => u.EmailAddress == emailAddress); 

    if (user == null) 
    { 
     throw new ValidationException("User not found."); 
    } 
    else 
    { 
     // validates whether or not the password on the user record 
     // that was retrieved by the query matches the password entered at login 
     return Hashing.ValidatePassword(Password, user.Password); 
    } 
+0

我明白你對電子郵件地址的意思,但你能詳細說明第一部分嗎? – Ortund

+0

我的登錄Post方法傳遞'User user'作爲第一部分,以便通過具有電子郵件地址的我的用戶模型的實例。這就是查詢的電子郵件地址來自哪裏。在這一點上,我想我需要檢查User.Identity是否爲空,但我不知道如何做到這一點 – Ortund

+0

現在我遇到了防僞系統的麻煩......所提供的身份鍵入'System.Web.Security。FormsIdentity'被標記爲IsAuthenticated = true,但沒有Name的值。默認情況下,防僞系統要求所有經過身份驗證的身份都有唯一的名稱。如果無法爲此標識提供唯一名稱,請考慮將靜態屬性AntiForgeryConfig.AdditionalDataProvider設置爲可爲當前用戶提供某種形式的唯一標識符的類型的實例。[ – Ortund