2011-05-06 48 views
1

首先,这不是一个关于的问题如何获取用户的IP地址,因为我知道该怎么做。关于保持用户“最后的IP地址”的建议

基本上,我的网站(ASP.NET MVC 3 Web应用程序)的管理员需要能够阻止某个IP地址提交用户内容。所以我在我们的系统中存储了针对用户的“IP地址”。凉。

我的问题是:

时(例如在什么时间,页面生命周期事件),我应该检查用户当前的IP地址,并保存到数据库中?

此刻,我正在考虑使用会话。也就是说,当我第一次创建会话时(例如Session_OnStart()),请抓住用户的IP地址并将其保存在会话中。然后,当会话结束时(例如Session_OnEnd()),我看到会话中的IP地址是否与数据库的IP地址不同。如果是,更新数据库。

在我们使用是InProc时刻,但有一个很好的机会,我们会去的StateServer以后 - 和MSDN指出的Session_OnEnd只适用于是InProc。所以这可能是一个问题。

这种方法的任何想法/替代方案?

编辑

所以我试图用Session_OnStart()尝试做以下事情:

如果用户通过认证,获得他们的IP地址,从数据库中获取他们的最后一个IP,如果他们不同,更新数据库。

但问题似乎是:Session_OnStart运行以前Application_AuthenticateRequest - 所以它从来没有经过“被认证”检查。

一个很好的例子是,如果用户登录到我的网站 - 使用Forms Auth,它设置一个有效期限为一周的cookie(例如)。

然后几天后他们回来了 - Session_OnStart被解雇 - 但他们还没有通过身份验证。即使cookie存在 - 它尚未处理到http上下文中。

因此,Session_OnStart看起来像一个没有去 - 任何其他的想法?

+0

我不明白你为什么需要将IP地址存储到数据库中。 – 2011-05-06 10:11:49

+0

@Carl R - 因为管理员可能会看到一个特定的IP地址在我的网站上发送了垃圾内容,并且他们创建了不同的用户。所以这样,我可以通过IP地址禁用所有帖子 - 例如'UPDATE Posts SET Disabled = 1 WHERE IpAddress = Blah' – RPM1984 2011-05-06 23:40:01

回答

0

因为它是asp.net MVC,你希望它针对所有的要求运行,我会考虑考虑使用一个全球行动过滤器像这里所描述的一个http://weblogs.asp.net/gunnarpeipman/archive/2010/08/15/asp-net-mvc-3-global-action-filters.aspx

+1

是的,我可以做到这一点。但是,我会在每次请求时都这样做。我认为用户的IP地址在一次浏览器会话期间并不会真正改变。更有可能他们会去某个地方的另一台计算机,在这种情况下会创建一个新的会话。对每一个请求做这件事情,虽然是傻瓜式的,但似乎有些过火。尽管这是一个选项..(最坏的情况下) – RPM1984 2011-05-06 05:48:49

+0

加上我不能真正对数据库做每个请求以获得他们的最后一个IP。我需要“缓存”某处。这就是为什么我最初的想法是会议。 – RPM1984 2011-05-06 05:57:16

+0

毕竟,由于我的编辑中声明的authenticate_request和session_onstart问题,最终导致您的方法正常运行。将添加完成代码,但接受你的。谢谢 – RPM1984 2011-05-09 00:44:27

1

会不会有在短短的登录问题ip在会话开始时而不是结束?就像你说的那样,在会话期间ip不会改变。

0

我猜你正在做数据库中的比较,看你的问题。

为了简单起见,我的建议是在web.config中保留阻止列表,并在需要时比较传入的ID。

如果您需要将阻止列表保存在数据库中,我会说使用缓存类缓存阻止列表一段合理的时间,并将ip与代码中的阻止列表进行比较,而不是在数据库中。

+0

身份证使用DB +缓存。保持在web.config中将很快变得难以管理,并且会导致部署噩梦,并且还会导致应用程序在更新时重新启动。 – UpTheCreek 2011-05-06 10:45:03

+0

是的,无法使用网络配置。这不是一个真正的“阻止列表”,随着时间的推移而逐渐形成。这是一次需要手动完成的事情,例如,我们看到这个特定的IP正在做坏事,所以我们根据他们的IP清除了数据库中的数据。我们不会“阻止”来自该IP的新内容。这只是“跟踪”。该操作在需要时手动进行 – RPM1984 2011-05-06 23:42:38

1

已接受@ lomaxx的答案 - 但认为我会为他人添加我自己的,以及为什么这是必需的推理。

解决方案:对每个请求执行的全局操作过滤器。

(简体)代码:

public class UserTrackingFilterAttribute : ActionFilterAttribute 
{ 
    public override void OnResultExecuted(ResultExecutedContext filterContext) 
    { 
     // If the user isn't authenticated or we have already tracked IP this session, bubble back up to base context. 
     if (!Authenticated || HaveTrackedIpAddressThisSession) 
     { 
      base.OnResultExecuted(filterContext); 
      return; 
     } 

     // Get the users current ip address. 
     var currentIp = HttpContext.Current.Request.CurrentIpAddress(); // extension method to read server variables, cater for proxy, etc 

     // Get the users last known ip address from repository. 
     var userService = ObjectFactory.GetInstance(typeof(IUserService)) as IUserService; 
     var unitOfWork = ObjectFactory.GetInstance(typeof(IUnitOfWork)) as IUnitOfWork; 
     if (userService == null || unitOfWork == null) return; 

     // See if the user's ip has changed. 
     var currentUser = userService.FindById(CurrentUserId); 
     if (currentUser == null || (currentUser.LastIpAddress != null && IPAddress.Parse(currentUser.LastIpAddress).Equals(currentIp))) 
     { 
      // User cannot be found or IP hasn't changed - set session key and bubble back up to base context. 
      HaveTrackedIpAddressThisSession = true; 
      base.OnResultExecuted(filterContext); 
      return; 
     } 

     // User's ip has changed - update ip address. 
     currentUser.LastIpAddress = currentIp.ToString(); 

     // Save. 
     userService.Save(currentUser); 

     // Commit. 
     unitOfWork.Commit(); 

     // Update session key. 
     HaveTrackedIpAddressThisSession = true; 
    } 
} 

“CurrentUserId” 和 “HaveTrackedIpAddressThisSession” 是私有属性来缩短该方法的代码。基本上他们分别阅读HttpContext.Current.User.IdentityHttpContext.Current.Session["someKey"]

为什么我需要一个全球行动过滤器在一个Global.asax事件:,因为我的逻辑需要一个Http主体存在,我不能在那个时候使用Session_OnStart以来,窗体身份验证Cookie尚未解密成主要身份。因此,尽管这会在每个页面请求上运行,但会话“标志”缓解了这种开销。