2011-05-06 21 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尚未解密成主要身份。因此,儘管這會在每個頁面請求上運行,但會話「標誌」緩解了這種開銷。