2

我正在.Net MVC4 中构建一个网站,并尝试使用 CustomPrincipal 对象实现我自己的表单身份验证。

这是我的登录方法...

public void Login(string email)
{
    var user = _userManager.GetUserByEmail(email);

    var encryptedCookieContent = FormsAuthentication.Encrypt(new FormsAuthenticationTicket(1, user.Email, DateTime.Now, DateTime.Now.AddMinutes(FormsAuthentication.Timeout.TotalMinutes),
        false, user.Id + "|" + user.AccountId + "|" + user.RoleId + "|" + user.Role.Name, FormsAuthentication.FormsCookiePath));

    var formsAuthenticationTicketCookie = new HttpCookie(FormsAuthentication.FormsCookieName, encryptedCookieContent)
    {
        Domain = FormsAuthentication.CookieDomain,
        Path = FormsAuthentication.FormsCookiePath,
        HttpOnly = true,
        Secure = FormsAuthentication.RequireSSL
    };

    HttpContext.Current.Response.Cookies.Add(formsAuthenticationTicketCookie);
}

这是我的自定义校长

public class CustomPrincipal : IPrincipal
{
    public CustomPrincipal(IIdentity identity, int userId, int accountId, string role, int roleId)
    {
        Identity = identity;
        Role = role;
        RoleId = roleId;
        UserId = userId;
        AccountId = accountId;
    }

    public bool IsInRole(string role)
    {
        return Role == role;
    }

    public bool IsInRole(int roleId)
    {
        return RoleId == roleId;
    }

    public IIdentity Identity { get; private set; }

    public string Role { get; private set; }
    public int RoleId { get; private set; }

    public int UserId { get; private set; }
    public int AccountId { get; private set; }
}

我没有实现 Identity 的自定义实例,我只是重用了 GenericIdentity。在我的 Global.asax 文件中,我的 Application_AuthenticateRequest 方法像这样安装...

protected void Application_AuthenticateRequest(Object sender, EventArgs e)
{
    if (Request.IsAuthenticated)
    {
        var formsCookie = Request.Cookies[FormsAuthentication.FormsCookieName];
        if (formsCookie != null)
        {
            var ticket = FormsAuthentication.Decrypt(formsCookie.Value);
            var principal = PrincipalConfig.CreatePrincipal(ticket);
            System.Web.HttpContext.Current.User = Thread.CurrentPrincipal = principal;
        }
    }
}

PrincipalConfig.CreatePrincipal 是将我的自定义主体对象放在一起的方法。这基本上只是填写 userData ......就像这样......

public static CustomPrincipal CreatePrincipal(FormsAuthenticationTicket ticket)
        {
            var userData =  ticket.UserData.Split('|');
            var principal = new CustomPrincipal(new GenericIdentity(ticket.Name), Convert.ToInt32(userData[0]), Convert.ToInt32(userData[1]), userData[3], Convert.ToInt32(userData[2]));
            return principal;
        }

现在,回到 global.asax 文件中的 Application_AuthenticateRequest,您可以看到我正在使用我新创建的 CustomPrincipal 对象并将其分配给 System.Web.HttpContext.Current.User。

这样做之后,如果我还在 Application_AuthenticateRequest 方法中将以下内容放在即时窗口中......

System.Web.HttpContext.Current.User as CustomPrincipal

正如我所期望的那样,我在我的 CustomPrincipal 对象中显示了所有数据。

但是,如果我稍后(在其他一些控制器操作中)尝试访问 System.Web.HttpContext.Current.User 并将其转换为 CustomPrincipal 它将返回 null。

同样,对于应用程序中发出的每个请求,我都能够从 Application_AuthenticateRequest 方法内的 FormsAuthentication cookie 中解密 FormsAuthenticationTicket,并找到我的所有 UserData。因此,似乎正在创建并正确读取 cookie。但是,当新的 CustomPrincipal 被分配给 System.Web.HttpContext.Current.User 时,从那个时候到我尝试在另一个控制器内再次访问它时似乎存在某种断开连接。

谁能看到我在这里可能做错了什么?

如果我需要澄清任何事情,请告诉我。

谢谢

4

1 回答 1

0

我不确定你正在使用

Request.IsAuthenticated

正确。

Request.IsAuthenticated 属性本质上返回与 Context.User.Identity.IsAuthenticated 属性相同的值。在您的代码中,它应该始终返回 false,因此分配自定义主体的代码将永远不会触发。

您可以通过在控制器方法中设置断点并检查代码中 Context.Current.User 的类型来稍微调试一下。是通用身份吗?如果是这样,您的校长从未被分配。

于 2013-09-23T22:46:51.177 回答