2013-09-26 63 views
4

我試圖用南希作爲ASP.NET MVC的替代品來實現一個非常簡單的秒殺。南希的表單驗證不能與AJAX登錄請求一起工作

它應該使用用戶名(無密碼)並在同一登錄頁面上提供有意義的錯誤消息,而不需要刷新。如果登錄成功,則響應包含要導航到的URL。

的POCO的迴應是這樣的:

public class LoginResponseModel 
{ 
    public bool IsSuccess { get; set; } 
    public string RedirectUrl { get; set; } 
    public string ErrorMessage { get; set; } 
} 

的JS處理程序登錄請求:

$.ajax({ 
     url: '/login', 
     type: "POST", 
     data: { UserName: username } 
    }).done(function (response) { 
     if (response.IsSuccess) { 
      showSuccess(); 
      document.location.href = response.RedirectUrl; 
      return; 
     } 
     showError(response.ErrorMessage); 
    }).fail(function (msg) { 
     showError("Unable to process login request: " + msg.statusText); 
    }); 

我遇到的問題是與南希的基於表單的身份驗證。我已經瀏覽了六本不同的教程,這些教程幾乎都做了同樣的事情,並且通過了南希認證演示。他們都有一個共同點,那就是他們依賴於LoginAndRedirect擴展方法。我不想返回重定向。我想返回登錄嘗試的結果並讓客戶端處理導航。

的IUserMapper實現我使用:

public class UserMapper : IUserMapper 
{ 
    public IUserIdentity GetUserFromIdentifier(Guid identifier, NancyContext context) 
    { 
     // Don't care who at this point, just want ANY user... 
     return AuthenticatedUser {UserName = "admin"}; 
    } 
} 

我的LoginModule行動的相關部分:

var result = _userMapper.ValidateUser(input.AccessCode); 

if (result.Guid != null) this.Login(UserMapper.GUID_ADMIN, expiry); 

return Response.AsJson(result.Response); 

但對於後續的請求Context.CurrentUser總是空。

如果我將下面的方法添加到Nancy.Demo.Authentication.Forms示例中,它會重現我在我自己的項目中看到的行爲,從而導致我相信LoginWithoutRedirect無法正常工作。

Get["/login/{name}"] = x => 
{ 
    Guid? userGuid = UserDatabase.ValidateUser(x.Name, "password"); 
    this.LoginWithoutRedirect(userGuid.Value, DateTime.Now.AddYears(2)); 
    return "Logged in as " + x.Name + " now <a href='~/secure'>see if it worked</a>"; 
}; 

回答

3

問題原來是Context.CurrentUser FormsAuthentication取決於如果你沒有返回NancyModule.Login()響應沒有設置的cookie。

var result = _userMapper.ValidateUser(input.AccessCode);    
if (result.IsSuccess) { 
    this.LoginWithoutRedirect(result.Guid); 
} 
return Response.AsJson(result); 

在這個例子中,LoginWithoutRedirect調用返回與Cookie集Response對象。爲了在Ajax場景中我有一個包含authToken屬性添加到LoginAjaxResponse類處理這個問題,然後通過cookie的,像這樣:

var result = _userMapper.ValidateUser(input.AccessCode);    
var response = Response.AsJson(result); 
if (result.IsSuccess) { 
    var authResult = this.LoginWithoutRedirect(result.Guid); 
    result.AuthToken = authResult.Cookies[0].Value; 
} 
return Response.AsJson(result); 

在客戶端,Ajax響應處理程序更改爲(假設使用jQuery cookie plugin

$.ajax({ 
    url: '/login', 
    type: "POST", 
    data: { UserName: username } 
    }).done(function (response) { 
    if (response.IsSuccess) { 
     showSuccess(); 
     $.cookie("_ncfa", response.AuthToken); // <-- the magic happens here 
     document.location.href = response.RedirectUrl; 
     return; 
    } 
    showError(response.ErrorMessage); 
}).fail(function (msg) { 
    showError("Unable to process login request: " + msg.statusText); 
}); 

的的authToken是已經被加密和base64編碼的啓用將首先檢查該身份驗證令牌的cookie this.RequiresAuthentication()後續請求的GUID。

  • 如果沒有 「_ncfa」 Cookie是目前,UserMapperGetUserFromIdentifier()永遠不會被調用。

  • 如果在base64解碼和解密時,Context.Request.Cookies["_ncfa"]中的值不會導致有效的GUID,則永遠不會調用GetUserFromIdentifier()

  • 如果不調用GetUserFromIdentifier(),則Context.CurrentUser從不設置。

如果你想爲工作的例子是在GitHub源。

+1

您也可以在響應中設置cookie,以避免必須將其設置在客戶端中。 例如: foreach(var c in authResult.Cookies)response.Cookies.Add(c); –

2

LoginAndRedirect只有一種選擇,也有不重定向(LoginWithoutRedirect)等效的方法,或者一個它是否是一個Ajax請求拿起,並適當地處理它(登錄)。這同樣適用於註銷。

這全部覆蓋在the documentation的詳細內容中。

+0

如果我理解正確的文件,我使用'登錄提供的示例()'應依次調用'LoginWithouRedirect',因爲它是一個AJAX請求。我也嘗試明確使用'LoginWithouRedirect',並且沒有設置'Context.CurrentUser'。 – nathanchere

+0

你確定你沒有對加密設置犯規嗎?每次請求都會收到和發送Cookie嗎? –

+0

我沒有做任何加密設置。現在我非常有信心,它沒有像我在Nancy.Demo.Authentication.Forms代碼中那樣表現出它的表現,並且添加了一個新的登錄操作,它展現了我在我自己的項目中看到的相同行爲 - 已經更新了相應的問題 – nathanchere