某些場景下,但願用戶只能從限定的IP地址上登入系統,姑且勿論限定IP登陸能帶來多少安全性上的改善,咱們來試試在使用Spring Security安全框架下,如何實現。java
有人確定會提出一個方案,你看,簡單,只要AuthenticationManager配置裏,增長一個AuthenticationProvider就能夠了,固然,這個是個很好的方案,也很容易實現,只要自定義AuthenticationProvider,在其authenticate方法裏實現邏輯就能夠了。而我在這裏要說的是一種更爲簡單的辦法,知足基本設計要求:web
在本地認證庫裏同時可配置IP限定規則正則表達式
IP限定規則能夠簡單支持:單個IP;逗號,分號分割的多個IP;IP地址範圍(同時支持多個定義)安全
驗證錯誤時拋出異常
框架
由於我採用的是本地庫的認證,使用的是DaoAuthenticationProvider,且自定義了UserDetailsService,能夠從UserDetailsService中讀取出用戶對應的限定IP配置,而後要作的是,咱們繼承DaoAuthenticationProvider自定義一個ExDaoAuthenticationProvider,重載其additionalAuthenticationChecks(UserDetails userDetails, UsernamePasswordAuthenticationToken authentication)方法,進行IP範圍check,以下爲代碼片斷:
ide
//省略imports public class ExDaoAuthenticationProvider extends DaoAuthenticationProvider { // 框架MessageSource private MessageSourceAccessor exmessage = ExtrasMessageSource.getAccessor(); @Override protected void additionalAuthenticationChecks(UserDetails userDetails, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException { //執行父類裏的檢查 super.additionalAuthenticationChecks(userDetails, authentication); //web,取得遠程ip String remoteAddress = null; Object details = authentication.getDetails(); if (details instanceof WebAuthenticationDetails) { WebAuthenticationDetails webDetails = (WebAuthenticationDetails) details; remoteAddress = webDetails.getRemoteAddress(); } // 例行null檢查遠程ip,若空,能夠直接返回或異常 if (remoteAddress == null || remoteAddress.trim().length() == 0) { throw new BadCredentialsException( exmessage .getMessage("framework.security.notAuthorizedIp")); } String validAddress = null; // ... ... 取得限定IP設定,能夠從UserDetails裏讀取或其餘方法,省略...... {validAddress = ... ...} //若是未限定ip,返回 if (validAddress == null || validAddress.trim().length() == 0) { return; } //檢查ip有效性 if (!validateRemoteAddress(validAddress, remoteAddress)) { throw new BadCredentialsException( exmessage.getMessage("framework.security.notAuthorizedIp")); } } private boolean validateRemoteAddress(String validAddress, String remoteAddress) { // 逗號,分號分割多個ip String[] address = validAddress.split(",|;"); if (address != null && address.length > 0) { for (String addr : address) { if (match(addr, remoteAddress)) return true; } } return false; } private boolean match(String addr, String remoteAddress) { // 用各類正則表達式等驗證IP有效性,省略... ... if (remoteAddress.matches(addr)) { return true; } ... ... // 圍在有效IP裏,則false return false; } }
最後,ExDaoAuthenticationProvider替換原配置,運行web應用,就能夠完成對遠程用戶登陸IP的限制了,非受權IP處登陸,系統會拋出異常,界面顯示給用戶錯誤信息。設計
經過上述辦法,能夠快速簡單的實現基於本地認證庫的IP限定邏輯,你們如有更好的實現方法,歡迎分享... ...code