4

我正在尝试使用 Nancy 作为 ASP.NET MVC 的替代方案来实现一个非常简单的尖峰。

它应该采用用户名(无密码)并在同一登录页面上提供有意义的错误消息,而无需刷新。如果登录成功,则响应包括要导航到的 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);
    });

我遇到的问题是 Nancy 的基于表单的身份验证。我已经浏览了六种不同的教程,它们或多或少都做同样的事情,并且浏览了 Nancy 身份验证演示。它们的共同点是它们都依赖于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>";
};
4

2 回答 2

3

问题原来是Context.CurrentUserFormsAuthentication 取决于如果您不返回NancyModule.Login()响应则未设置的 cookie。

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

在此示例中,LoginWithoutRedirect调用返回一个Response带有 cookie 集的对象。为了在 Ajax 场景中处理这个问题,我必须向LoginAjaxResponse类添加一个 AuthToken 属性,然后像这样传递 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 插件

$.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 编码的 GUID。启用的后续请求this.RequiresAuthentication()将首先检查此身份验证令牌 cookie。

  • 如果不存在“_ncfa”cookie,则永远不会调用UserMapper's 。GetUserFromIdentifier()

  • 如果在Context.Request.Cookies["_ncfa"]base64 解码和解密时 in 的值不会产生有效的 GUID,GetUserFromIdentifier()则永远不会调用。

  • 如果GetUserFromIdentifier()未调用,Context.CurrentUser则永远不会设置。

如果你想要一个工作示例的源代码,它位于GitHub 上

于 2013-09-27T04:25:00.993 回答
2

LoginAndRedirect 只是一种选择,有不重定向的等效方法(LoginWithoutRedirect),或者一种判断它是否是 AJAX 请求并适当处理它的方法(登录)。这同样适用于注销。

文档中详细介绍了所有这些内容。

于 2013-09-26T08:15:29.420 回答