zoukankan      html  css  js  c++  java
  • 项目经验分享(中)

       上篇(项目经验分享(上))总结了一些琐碎的小经验,这篇来讲一讲在项目中如何解决一个问题,说它是问题,只是针对我个人来讲,因为以前没有处理过类似的问题,主要是分享下我处理这个问题的过程及方法。
       
       项目技术背景:
       1:asp.net mvc 3 项目
       2:登录机制是采用membership
       3:认证采用Forms验证
       4:EntityFramwork做为数据访问
       
       
       问题描述:
       当我们的项目部署到租用的美国服务器上后 (据说是一个云服务,说的通俗点可能就是在虚似机上的一个IIS站点)出现了用户需要频繁登录的现象,具体来讲大约在10分钟之内就会要求用户重新登录。
       
       阶段一:
       问题是客户发现的,他们在UAT时,提到了用户需要频繁登录的问题。
       
       我的反应:
       由于我提供给大家UAT的是一个公共帐号,大家均使用同一帐号登录,可能会发生不同的人注销同一帐号的现象,可能存在相互的影响,故建议用户重新启用一个全新的帐号。
       
       问题:上面的项目技术背景提到了是采用Forms验证,而我们是采用默认的Forms验证机制,即将数据存储在客户端,以cookie的形式,故即使多人使用同一帐号,发生不同用户注销同一帐户的现象,也不会影响到其它的用户的登录状态。这也是当时没太注意的地方,没找出问题本质的情况下,凭经验下结论。
       
       阶段二:
       客户再次反应此问题,而且他们明确了自己使用的帐户是私人的。
       
       我的反应:
       意识到事情的严重性,马上组织测试人员做了仔细的测试,发现问题确实存在,当时就开始着手解决这个问题,毕竟这属于一个优先级最高的问题。
       
       经过和同事讨论以及网上搜索后得到如下方案:
       1:在web.config中设置forms的一个time out
       我们原来的配置如下:
      
    <forms loginUrl="Account/LogOn" defaultUrl="Account/RaceTemplate">
       但发现这个值即使不设置,默认时间也有30分钟,远大于我们出现问题的10分钟,但抱着试试看的心情,将之调大到300分钟,问题依旧。
       
       2:也许和session的设置有关系
       我也忘记当时为什么联想到session了,也许是我原来的项目都是基于sessio机制的验证原因吧,但同样的问题是,session的默认机制也是存储在进程中,且超时时间为20分钟,我同样抱着试试的心情,将这个数值调整到300分钟,问题依旧。
       

       3:考虑是否和Membersip的设置有关系

       因为我们登录是采用membership,是否是它有相应的设置,于是开始咨询同事,结果是,我们的项目是第一个基于membership的项目,网上搜索无果。

       

       问题:这是没有搞清楚Forms验证的机制,错误的想法,误认为和mebership本身有关系。

       4:怀疑服务器提供商的产品会定期回收我们站点的应用程序池
       这是有依据的,因为我们在自己的本地测试机器上做测试,一点问题都没有,从不出现频繁登录的现象。于时让相关同事发邮件咨询服务器提供商,以等待结果。
       
       5:做好服务器提供商无法给出满意答案的准备。
       如果应用程序池会被定期回收,而服务器提供商无法即时解决被回收的问题时,那么我们尝试将session存入在数据库中。毕竟我们不能一直等别人的反馈。
       
       问题:这也是没有搞清楚Forms验证的机制,错误的想法,误认为和session有关系,好的是,我们当时只有这个想法 ,并没有着手去做,因为它有如下问题:
       
       1):这是一种逃避问题的方式。
       即使存储在进程中有问题,那么我们需要找出其中的原因,而不能因为它有问题就想其它的方法,没有治本。
       2):session存储中数据库中需要部署很多的数据库脚本。
       这样一来是工作量增大,二来对现在的系统会有一定影响。
       3):我们租用的数据库空间很少,只有几十M,怕影响业务数据的使用。    

       从技术手段下手

       由于服务器提供商未在短时间内给出正确答案,我开始从技术手段下手,从根本上排查原因。
       此次对Forms验证做了比较详细的了解,排除了session和membership的干扰,讲的简单点Forms验证原理是这样的:
       
       首先创建一个用户的票据,经过相应算法的加密,最后将票据保存在cookie中,验证的过程是首先读取用户cookie,如果存在的话,再将票据解密,如果没有问题即验证通过。
       
       于时,开始手动编写登录逻辑,原来是直接调用授权代码:
      

    FormsAuthentication.SetAuthCookie(model.UserName, true);

       
       现在开始尝试以编程方式来授权,即不从配置文件中读取相关设置,于时有了如下代码:
      

    FormsAuthenticationTicket authTicket = new FormsAuthenticationTicket(1, UserName, DateTime.Now, DateTime.Now.AddHours(20),            

    true, UserRole); // User datastring encryptedTicket = FormsAuthentication.Encrypt(authTicket); //加密
                
    // 存入Cookie            HttpCookie authCookie = new HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket);
                authCookie.Expires = authTicket.Expiration;
                Response.Cookies.Add(authCookie);

                
        兴奋的部署上去之后,仍然是失望而归。
        
        再次尝试对读取cookie做手动编码:
        

    string cookieName = FormsAuthentication.FormsCookieName;
                //get Cookie.
                HttpCookie authCookie = Context.Request.Cookies[cookieName];
                if (null == authCookie)
                    return;
                FormsAuthenticationTicket authTicket = null;
              
                authTicket = FormsAuthentication.Decrypt(authCookie.Value);
                if (null == authTicket)
                    return;

             
                string[] roles = authTicket.UserData.Split(new char[] { ',' });
                FormsIdentity id = new FormsIdentity(authTicket);
                GenericPrincipal principal = new GenericPrincipal(id, roles);
               
                Context.User = principal;

                
         还是失败则归。
         
         最后在网上查看到,如果应用程序池被回收,它会重新分配一个machineKey,而这个machineKey会影响到cookie票据,它有两个重要的属性:
         validationKey,
         decryptionKey
        它和上面说到的对票据数据的加密,解密,验证问题有直接关系,这里我就不多讲了。如果应用程序池被回收,那么对应的validationKey就会不相同,即与之前的cookie就无法匹配上,这样就造成了我们需要频繁登录。
         
         微软也非常建议在web项目中配置明确的machineKey,理由如下:
         1:可以解决站点重启,或者是应用程序池回收造成用户验证失败的现象。
         2:如果是负载均衡的站点,那么他们之间最好也共用同一明确的machineKey。
         
        问题总算找到了,问题也解决了,现在的问题就是应用程序池为什么会被定期回收,这个问题的解释就不是我们开发组能回答的问题了,我们完成解决了对他们的依赖,即使他们不做解释不做处理,我们的问题同样也得到了解决,从而不会影响到用户体验以及最终项目上线。    
        

    总结:
             之所以这样一个问题困扰我们这么些天(大约一周时间),首要原因是没有详细了解Forms验证的机制,这是我做的第一个Forms验证项目,所以走了些弯路,容易凭经验被一些其它信息所干扰。其次是租用服务器问题,我们对于他的定期回收原因,还在排查中,如果不定期回收,此问题也不会出现。所以当出现修改默认值不起作用时,请转换你的思维方式去尝试从不同角度分析问题。

        参考资料:http://msdn.microsoft.com/en-us/library/ff649308.aspx

  • 相关阅读:
    js 文件的操作
    js重点基础知识 以及小案例_最简单的轮播图 简单的动态表格( encodeURIComponent()编码比 encodeURI()编码)
    2阶——数据库连接池 c3p0 , druid, dbcp (其实所有的连接池都实现了dataSource接口,就可以调用getconnection方法)
    2阶——JDBC,JDBCTemplate(操作数据库)
    vue + django 批量删除
    简单的模糊搜索 Vue + django
    vue 父子组件传参简单的分页
    vue 多对多反序列化上传图片
    模型里的 抽象类 表继承
    django 多对多反序列添加
  • 原文地址:https://www.cnblogs.com/ASPNET2008/p/2552400.html
Copyright © 2011-2022 走看看