在JAVA裡HttpServletRequest介面提供了getRemoteAddr()方法來擷取用戶端IP地址(其實是繼承自ServletRequest介面的),使用很簡單,方法如下:
假設已有HttpServletRequest對象request(Jsp中預設)
String ipaddress = request.getRemoteAddr();
但是這一方法有致命缺陷,就是不能穿透Proxy 伺服器。當系統架構中使用了Proxy 伺服器時,上述方法抓到的就是Proxy 伺服器的IP地址。在大中型J2EE架構的項目開發中,Java應用伺服器常常需要使用叢集與代理,故而上述方法便不可行了。筆者曾曆查J2EE技術有關資料,未能發現可以一箭貫透Proxy 伺服器的直接可用的IP抓取方法。但J2EE是強大的,解決之道當然是不缺的,這裡介紹一下我們的解決方案--使用帶數位簽章的Applet。
我們知道Applet是下載到用戶端,在用戶端的JVM上啟動並執行,當Applet運行不涉及用戶端的本地資源時使用Applet是個小Case(許多股票網站裡動態顯示交易曲線的技術就是這一招),但當要擷取本地資源資訊(即便只是抓個IP地址)時,就一定要對APPLET進行數位簽章和認證(詳情參見有關Java安全機制)。
帶數位簽章和認證的APPLET開發過程如下:
(1)開發APPLET的Java來源程式並對其進行編譯。
抓取本機(即客戶機)IP的APPLET代碼如下:
import java.applet.*;
import java.net.*;
import java.awt.*;
public class getipapp extends Applet
{
public String myip()
{
String ipd="";
try{
//使用抓取本機Ip的方法getLocalHost(),返回一個InetAddress對象
InetAddress addr=InetAddress.getLocalHost();
//從InetAddress對象中取出資料放到byte類型的數組中
byte[] ipAddr=addr.getAddress();
int i=0;
int ipget=0;
//組裝String類型的IP地址
while(i<ipAddr.length){
ipget=ipAddr[i];
//對返回的數值進行轉換整理
if(ipget<0){ipget=256+ipget;}
if(i==0){
ipd=ipd+ipget;
}else{
ipd=ipd+"."+ipget;
}
i++;
}
}catch(UnknownHostException e){
}
return ipd;
}
public getipapp()
{
}
//Initialize the applet
public void start()
{
}
}
(2)用JAR工具對類檔案和資源檔進行封裝。
目前的目錄下:
jar cvf myip.jar *.class
(3)用keytool建立公開金鑰和密鑰,產生X。509V1簽署憑證,輸出認證。
目前的目錄下:
keytool -genkey -keystore myip.keystore -alias myip
說明:keystore將用來存放密匙(private keys)和公用鑰匙的認證,此命令產生了一個名為myip.keystore的keystore檔案,接著這條命令,系統會接著有提示的要求填寫若干內容,比如建立人、公司名稱、地址、設定的密碼等等,隨便填寫後完成。
(4)將公用鑰匙匯入到安全性憑證cer檔案中。
目前的目錄下:
keytool -export -keystore myip.keystore -alias myip -file myip.cer
說明:此命令產生一個名為myip.cer的安全性憑證檔案(這也是用戶端運行訪問本地資源的applet時需要的檔案),使用命令當中會提示你輸入密碼,輸入先前設定的密碼即可。
至此,一個帶數位簽章和認證的APPLET開發完成。此APPLET運行時一旦通過用戶端的許可驗證(詳情下述),便能抓取到客戶機的IP地址,然後是將此地址傳遞到伺服器上。我們在實踐中使用javascript指令碼直接與applet通訊,將抓取到的IP地址存放到頁面元素中,然後通過表單將IP地址提交到伺服器,方法如下。
(5)WEB(一般是登入頁)擷取applet參數的設定方法:
在<body>與</body>之間加入:
<applet code="getipapp.class" codebase = "" archive = "myip.jar"
width="0" height="0" name="getipapp">
</applet>
和<input type="hidden" name="iptxt">(這是網頁中用來存放applet參數的頁面元素)
很重要:
在<head>與</head>之間加入:
<SCRIPT LANGUAGE=javascript>
function getmyip()
{
//假設<input type="hidden" name="iptxt">元素在form1表單中
window.document.form1.iptxt.value=window.document.getipapp.myip();
}
</ SCRIPT >
說明:利用javascript中將applet視為頁面元素並提供簡單通訊的方法直接從頁面上取得applet擷取的用戶端IP地址,並通過表單提交給伺服器(方法略)。
現在,用戶端需要做的就是安裝jre虛擬機器(建議1.4.1以上版本),在Windows系統中成功安裝後在控制台中會看見一個"Java Plug-in"表徵圖,開啟該程式後在"瀏覽器"中確認將系統使用的瀏覽器鉤上(IE或NetScape)。重啟瀏覽器,訪問伺服器上裝有applet的網頁,此時會自動彈出安全性憑證的驗證資訊,當確認該認證可行後,帶有該認證的applet就可以在你的機器上為所欲為了(呵呵,也沒幹什麼,就打聽了一下你機器上的IP地址),同時在"Java Plug-in"的"認證→帶簽名的小程式"中會自動匯入你所簽發的安全性憑證。
說了這麼多,其實主要介紹了穿透Proxy 伺服器擷取用戶端IP的applet的一個完整方案。相信在J2EE架構下解決方案還很多,希望大家多多交流。(另外,這個方案中只擷取了原生主IP,若要取到原生所有IP則在applet的源碼中做些改動即可。)