IsAuthenticated是假的!奇怪的行为+审查问题

时间:2011-01-16 03:34:13

标签: asp.net authentication asp.net-membership forms-authentication

这是登录功能(在验证用户名和密码后,我将用户数据加载到“user”变量并调用Login功能:

public static void Login(IUser user)
{
    HttpResponse Response = HttpContext.Current.Response;
    HttpRequest Request = HttpContext.Current.Request;

    FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(1,
        user.UserId.ToString(), DateTime.Now, DateTime.Now.AddHours(12), false,
        UserResolver.Serialize(user));

    HttpCookie cookie = new HttpCookie(FormsAuthentication.FormsCookieName,
        FormsAuthentication.Encrypt(ticket));
    cookie.Path = FormsAuthentication.FormsCookiePath;

    Response.Cookies.Add(cookie);

    string redirectUrl = user.HomePage;

    Response.Redirect(redirectUrl, true);
}

UserResolver是以下类:

public class UserResolver
{
    public static IUser Current
    {
        get
        {
            IUser user = null;
            if (HttpContext.Current.User.Identity.IsAuthenticated)
            {
                FormsIdentity id = (FormsIdentity)HttpContext.Current.User.Identity;
                FormsAuthenticationTicket ticket = id.Ticket;
                user = Desrialize(ticket.UserData);
            }
            return user;
        }
    }

    public static string Serialize(IUser user)
    {
        StringBuilder data = new StringBuilder();
        StringWriter w = new StringWriter(data);
        string type = user.GetType().ToString();
        //w.Write(type.Length);
        w.WriteLine(user.GetType().ToString());
        StringBuilder userData = new StringBuilder();
        XmlSerializer serializer = new XmlSerializer(user.GetType());
        serializer.Serialize(new StringWriter(userData), user);
        w.Write(userData.ToString());
        w.Close();
        return data.ToString();
    }

    public static IUser Desrialize(string data)
    {
        StringReader r = new StringReader(data);
        string typeStr = r.ReadLine();
        Type type=Type.GetType(typeStr);
        string userData = r.ReadToEnd();
        XmlSerializer serializer = new XmlSerializer(type);
        return (IUser)serializer.Deserialize(new StringReader(userData));
    }
}

global.asax实现以下内容:

void Application_PostAuthenticateRequest(Object sender, EventArgs e)
{
    IPrincipal p = HttpContext.Current.User;
    if (p.Identity.IsAuthenticated)
    {
        IUser user = UserResolver.Current;
        Role[] roles = user.GetUserRoles();
        HttpContext.Current.User = Thread.CurrentPrincipal =
            new GenericPrincipal(p.Identity, Role.ToString(roles));
    }
}

第一个问题: 我做得对吗?

第二个问题 - 奇怪的是! 我传递给Login的用户变量有4个成员:UserName,Password,Name,Id。 当UserResolver.Current执行时,我得到了用户实例。 我决定更改用户结构 - 我添加了一个Warehouse对象数组。 从那时起,当UserResolver.Current执行时(登录后),HttpContext.Current.User.Identity.IsAuthenticated为false,我无法获取用户数据。 当我从用户结构中删除Warehouse []时,它再次开始正常,登录后HttpContext.Current.User.Identity.IsAuthenticated变为true。

这种奇怪行为的原因是什么?

2 个答案:

答案 0 :(得分:3)

首先,您不需要从Global.asax执行HttpContext.Current。 Global.asax派生自HttpApplication。所以你需要做的就是获得Context属性。这可能有助于使代码更清晰。

    //this is all you need in your global.asax
    void Application_PostAuthenticateRequest(Object sender, EventArgs e)
    {
        if(Context.User.Identity.IsAuthenticated)
        {
            var user = UserResolver.Current;
            Context.User = Thread.CurrentPrincipal = new UserWrapperPrincipal(user, Context.User.Identity);
        }
    }

    //this helper class separates the complexity
    public class UserWrapperPrincipal: IPrincipal, IUser
    {
        private readonly IUser _user;
        private readonly IIdentity _identity;

        public UserWrapperPrincipal(IUser user, IIdentity identity)
        {
            _user = user;
            _identity = identity;
        }

        private IList<string> RoleNames
        {
            get { return _user.GetUserRoles().Select(role => role.ToString()); }
        }

        public IIdentity Identity { get { return _identity; } }

        public bool IsInRole(string role) { return RoleNames.Contains(role); }

    }

根据您的错误,似乎问题是您的序列化功能或反序列化功能会破坏数据。但是,问题区域可能不是那些功能。序列化Warehouse对象(序列化复杂类型有时可能很棘手)或实际数组的序列化都存在问题。由于您使用的是默认的.NET XmlSerializer,因此有一篇很好的文章介绍了如何在http://www.diranieh.com/NETSerialization/XMLSerialization.htm自定义和控制处理不同对象的方式。

另外请注意,您确定这是将这些数据存储在应用程序中的最佳方式吗?存储用户ID和名称是有道理的。当您开始在cookie中存储复杂对象的序列化数组时,它可能表示您没有正确地解决问题。

答案 1 :(得分:1)

我猜你的代码是在某个地方的登录事件中,并且你构建了一个自定义表单身份验证。

您还需要在每个页面请求上从cookie构建User对象

public class AuthHttpModule : IHttpModule { 
    public virtual void Init(HttpApplication app) {
        app.AuthenticateRequest += new EventHandler(app_AuthenticateRequest);
    }
    private void app_AuthenticateRequest(object source, EventArgs e) {  
        HttpCookie cookie = HttpContext.Current.Request.Cookies[FormsAuthentication.FormsCookieName];
        if (cookie == null) {
            HttpContext.Current.User = null;
        } else {
            cookie = HttpContext.Current.Response.Cookies[FormsAuthentication.FormsCookieName];
            FormsAuthenticationTicket ticket = FormsAuthentication.Decrypt(cookie.Value);
            HttpContext.Current.User = new System.Security.Principal.GenericPrincipal(new FormsIdentity(ticket), new string[0]);
        }
        bool result = HttpContext.Current.Request.IsAuthenticated;
    }
}

修改

尝试将此添加到您的全局

void Application_AuthenticateRequest(Object sender, EventArgs e)
    HttpCookie cookie = HttpContext.Current.Request.Cookies[FormsAuthentication.FormsCookieName];
    if (cookie != null) {
        FormsAuthenticationTicket ticket = FormsAuthentication.Decrypt(cookie.Value);
        HttpContext.Current.User = new System.Security.Principal.GenericPrincipal(new FormsIdentity(ticket), new string[0]);
    }
}