基于 HTTP 的應用程序
java.net 包中的類和接口提供了可用于低層和高層網絡編程的 API。低層 API 可以讓你直接訪問網絡協議,但是為此你不得不使用低層的 TCP 套接字和 UDP 數據包。高層的 API (如 URL, URLConnection 和 httpURLConnection 等類) 可以使你更快的開發網絡應用,卻不需要寫很多代碼。
另一篇文章,《Network Programming with J2SE 1.4》會告訴你如何使用低層的套接字進行網絡編程。這篇文章的重點則放在如何使用 java.net 包中的高層 API 開發基于 HTTP 的應用程序。
這篇文章將有如下內容:
- 概覽 HTTP
- 概覽 java.net 包的高層 API
- 示例說明如何使用高層 API
- 制作一個可以下載股票行情的應用程序
- 演示如何提交數據到網頁服務器
- 概覽 HTTP 的驗證并展示如何保護你的網絡資源
- 提供代碼實例演示如何執行 HTTP 的驗證
概覽 HTTP
超文本傳輸協議 (Hypertext Transfer Protocol, HTTP) 是一個“請求-回應”的應用協議。這個協議支持一套固定的方法如 GET、POST、PUT、DELETE 等。一般用 GET 方法向服務器請求資源。這里有兩個 GET 請求的例子:
GET / HTTP/1.1
GET /names.html HTTP/1.1
另外,你可以使用 GET 和 POST 方法向服務器發送數據,它們向服務器發送數據的方式是不同的:
- GET 方法:輸入的數據將作為 URL 的一部分發送
- POST 方法:輸入數據作為一個獨立的實體發送
考慮一下下面的 HTML 表單:
<form action="http://www.javacourses.com/servlets/getMarks method="GET">
Student#:
<input type=text name=number size=30>
<input type=submit name=GetMarks value=GetMarks>
</form>
這個表單會提交到 http://www.javacourses.com/servlet/getMarks 由 Servlet 處理。該表單使用了 GET 方法來傳輸信息。如果用戶輸入一個學號——比如 556677——并點擊 GetMarks 按鈕,表單數據就會作為 URL 的一部分傳送到 Servlet 中。經過編碼之后的 URL 就是:http://www.javacourses.com/servlets/getMarks?number=556677。
在使用 POST 方法的情況下,傳輸數據時不會將數據作為 URL 的一部分;它們會作為一個獨立的實體來傳輸。因此,POST 方法更安全,你也可以用這個方法傳輸更多的數據。而且用 POST 傳輸的數據不一定要是文本,用 GET 方法傳輸的卻一定要是文本。
消息息格式
請求消息指定了方法名稱 (GET 或者 POST)、URL、協議版本號、頭部消息和可選消息。頭部消息也許會包含請求信息和客戶端信息,如接受的內容類型、瀏覽器名稱以及驗證數據。返回消息指定了協議版本、響應代碼和原因。不管執行是否成功,響應代碼和原因都會報告。一些響應代碼如下:
200 OK: Request succeeded. The requested resource can be found later in this message.
301 Moved Permanently: Requested resource has moved. New location is specified later in this message.
400 Bad Request: Request message is not understood by the server.
404 Not Found: Requested document is not found on this server.
關于 HTTP 和所有返回代碼的信息可以在 HTTP 1.1 規范 RFC2616 中找到。
下面是一個請求消息由瀏覽器到服務器的例子。這里請求的 URL 是 http://java.sun.com:
GET / HTTP/1.1
Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg,
application/vnd.ms-powerpoint, application/vnd.ms-excel,
application/msword, */*
Accept-Language: en-ca
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 5.01; Windows 98; YComp 5.0.0.0)
Host: java.sun.com
Connection: Keep-Alive
Cookie: SUN_ID=24.80.19.177:28346100732290;
SunONEUserId=24.80.19.177:86521021960770
然后這里是服務器對這個請求的回復消息:
HTTP/1.1 200 OK
Server: Netscape-Enterprise/6.0
Date: Mon, 14 Oct 2002 15:18:04 GMT
Content-type: text/html
Connection: close
概覽 java.net 包的高層 API
java.net 包中含有高層 API。它們實現了一些最常用的基于 TCP 的協議,如 HTTP 和 FTP 等。其中兩個主要的類是 URL 和 URLConnection。另一個有用的類是 HttpURLConnection,它是 URLConnection 的子類,支持 HTTP 的特性。
URL (Uniform Resource Locator,統一資源定位器) 是一個描述 Internet 中文檔 (或者其它常見的資源) 位置的地址。URL 的樣子就像這樣:
protocol://machineName:port/resource
注意 URL 類不是基于 HTTP 的,這一點非常重要。它支持 FTP、HTTPS 和 FILE
CNBIE BLOG
Java 高層網絡編程
原文:
Java 高層網絡編程
java.net 包中的類和接口提供了可用于低層和高層網絡編程的 API。低層 API 可以讓你直接訪問網絡協議,但是為此你不得不使用低層的 TCP 套接字和 UDP 數據包。高層的 API (如 URL, URLConnection 和 httpURLConnection 等類) 可以使你更快的開發網絡應用,卻不需要寫很多代碼。另一篇文章,《Network Programming with J2SE 1.4》會告訴你如何使用低層的套接字進行網絡編程。這篇文章的重點則放在如何使用 java.net 包中的高層 API 開發基于 HTTP 的應用程序。
這篇文章將有如下內容:
· 概覽 HTTP · 概覽 java.net 包的高層 API · 示例說明如何使用高層 API · 制作一個可以下載股票行情的應用程序 · 演示如何提交數據到網頁服務器 · 概覽 HTTP 的驗證并展示如何保護你的網絡資源 · 提供代碼實例演示如何執行 HTTP 的驗證
概覽 HTTP
超文本傳輸協議 (Hypertext Transfer Protocol, HTTP) 是一個“請求-回應”的應用協議。這個協議支持一套固定的方法如 GET、POST、PUT、DELETE 等。一般用 GET 方法向服務器請求資源。這里有兩個 GET 請求的例子:
GET / HTTP/1.1 GET /names.html HTTP/1.1
另外,你可以使用 GET 和 POST 方法向服務器發送數據,它們向服務器發送數據的方式是不同的:
· GET 方法:輸入的數據將作為 URL 的一部分發送 · POST 方法:輸入數據作為一個獨立的實體發送
考慮一下下面的 HTML 表單:
<form action="http://www.javacourses.com/servlets/getMarks method="GET"> Student#: <input type=text name=number size=30> <input type=submit name=GetMarks value=GetMarks> </form>
|
這個表單會提交到 http://www.javacourses.com/servlet/getMarks 由 Servlet 處理。該表單使用了 GET 方法來傳輸信息。如果用戶輸入一個學號——比如 556677——并點擊 GetMarks 按鈕,表單數據就會作為 URL 的一部分傳送到 Servlet 中。經過編碼之后的 URL 就是:http://www.javacourses.com/servlets/getMarks?number=556677。
在使用 POST 方法的情況下,傳輸數據時不會將數據作為 URL 的一部分;它們會作為一個獨立的實體來傳輸。因此,POST 方法更安全,你也可以用這個方法傳輸更多的數據。而且用 POST 傳輸的數據不一定要是文本,用 GET 方法傳輸的卻一定要是文本。
消息息格式
請求消息指定了方法名稱 (GET 或者 POST)、URL、協議版本號、頭部消息和可選消息。頭部消息也許會包含請求信息和客戶端信息,如接受的內容類型、瀏覽器名稱以及驗證數據。返回消息指定了協議版本、響應代碼和原因。不管執行是否成功,響應代碼和原因都會報告。一些響應代碼如下:
200 OK: Request succeeded. The requested resource can be found later in this message. 301 Moved Permanently: Requested resource has moved. New location is specified later in this message. 400 Bad Request: Request message is not understood by the server. 404 Not Found: Requested document is not found on this server.
|
關于 HTTP 和所有返回代碼的信息可以在 HTTP 1.1 規范 RFC2616 中找到。 下面是一個請求消息由瀏覽器到服務器的例子。這里請求的 URL 是 http://java.sun.com:
GET / HTTP/1.1 Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/vnd.ms-powerpoint, application/vnd.ms-excel, application/msword, */* Accept-Language: en-ca Accept-Encoding: gzip, deflate User-Agent: Mozilla/4.0 (compatible; MSIE 5.01; Windows 98; YComp 5.0.0.0) Host: java.sun.com Connection: Keep-Alive Cookie: SUN_ID=24.80.19.177:28346100732290; SunONEUserId=24.80.19.177:86521021960770
|
然后這里是服務器對這個請求的回復消息:
HTTP/1.1 200 OK Server: Netscape-Enterprise/6.0 Date: Mon, 14 Oct 2002 15:18:04 GMT Content-type: text/html Connection: close
|
概覽 java.net 包的高層 API
java.net 包中含有高層 API。它們實現了一些最常用的基于 TCP 的協議,如 HTTP 和 FTP 等。其中兩個主要的類是 URL 和 URLConnection。另一個有用的類是 HttpURLConnection,它是 URLConnection 的子類,支持 HTTP 的特性。
URL (Uniform Resource Locator,統一資源定位器) 是一個描述 Internet 中文檔 (或者其它常見的資源) 位置的地址。URL 的樣子就像這樣:
protocol://machineName:port/resource
注意 URL 類不是基于 HTTP 的,這一點非常重要。它支持 FTP、HTTPS 和 FILE 協議。所以,對于 URL 類來說,下面所有 URL 都是有效的。
http://java.sun.com http://localhost:8080/myApplication http://www.yahoo.com/index.html http://www.yahoo.com ftp://ftp.borland.com ftp://ftp.sun.com https://www.scotiaonline.scotiabank.com https://central.sun.net file:///C:/j2sdk1.4/docs/api/index.html
你在瀏覽器里輸入一個 URL 的時候,瀏覽器產生一個 HTTP GET (或者 POST) 命令尋找 (或者查詢) URL 請求的資源。如果沒有指定要查詢的的資源,被查詢的就會是默認文檔 (通常是 index.html)。
讀取 URL 的內容
讓我們以一個簡單的應用程序開始,它將會直接從 URL 讀取內容。不妨先嘗試一下使用低層的套接字來讀取,請看示例代碼 1。在這個例子中,用戶在命令行輸入資源的 URL,然后在 80 端口 (默認的 HTTP 服務器端口號) 打開一個套接字并建立相應的輸入輸出流。輸出流用來向 HTTP 服務器發送 HTTP 命令 (比如 GET),輸入流則用來讀取 HTTP 服務器的返饋。注意,在這個例子中,服務器回應的頭信息也會被讀入 (這是 URL 內容之外的東西)。
示例代碼 1: ReadURL1.java
import java.net.*; import java.io.*;
public class ReadURL1 { public static void main(String argv[]) throws Exception { final int HTTP_PORT = 80; if(argv.length != 1) { System.out.println("Usage: java ReadURL1 <url>"); System.exit(0); }
Socket socket = new Socket(argv[0], HTTP_PORT); BufferedWriter out= new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())); BufferedReader in= new BufferedReader(new InputStreamReader(socket.getInputStream())); out.write("GET /index.html HTTP/1.0\n\n"); out.flush(); String line; StringBuffer sb = new StringBuffer(); while((line = in.readLine()) != null) { sb.append(line); } out.close(); in.close(); System.out.println(sb.toString()); } }
// end code
|
你運行這個例子的時候請注意,URL 必須是一個域名如 java.sun.com 或者 IP 地址。不能加上 http:// 作為 URL 的一部分。如果你要解決這個問題,你就得解析輸入的內容并找出它使用什么協議,端口號和要請求什么資源。你也可以使用 URL 類,它提供了一些非常有用的方法,如 getProtocal、getPort、getHost 和 getFile 等。
使用 URL 類
要從 URL 讀取內容,可以用 URL 類非常容易的實現,就像示例代碼 2 所展示的那樣。這使得直接從 URL 讀取內容變得簡單。用這種方法讀取的內容不包含服務器回應的頭信息,所以不需要你去解析它們了。運行這個例子時要輸入有效的 URL ,就像 protocol://domainName:port/resource 這樣。URL 類會解析輸入的 URL 并處理低層的麻煩的工作。
示例代碼 2:ReadURL2.java
import java.net.*; import java.io.*;
public class ReadURL2 {
public static void main(String argv[]) throws Exception { if(argv.length != 1) { System.out.println("Usage: java ReadURL2 <url>"); System.exit(0); }
URL url = new URL(argv[0]); BufferedReader in= new BufferedReader(new InputStreamReader(url.openStream())); String line; StringBuffer sb = new StringBuffer();
while ((line = in.readLine()) != null) { sb.append(line); } in.close(); System.out.println(sb.toString());
}
}
|
在你運行 ReadURL2 的時候,你會看到你輸入的 URL 所請求的文檔內容命令窗口中顯示出來。
如果你想做除了讀取之外的其它事情,請使用 openConnection 來建立到 URL 的連接。這個方法返回一個 URLConnection 對象,你可以用這個對象來與 URL 通信,如讀、寫、查詢等。一但 openConnetion 方法創建了連接,你就可以使用 getContentType、getContentLength、getContentEncoding 等非常有用的方法了。
使用 URLConnection 類
我們現在要創建一個從 http://quote.yahoo.com 獲取股票信息的應用程序來演示如何使用 URLConnection。為了獲取特別的股票信息,用戶輸入股票標號 (比如 SUNW、IBM 或者 MOT),由應用程序從 Yahoo Quote 服務器獲取相應的股票信息。應用程序會顯示出該股票的名稱、價格和日期。
有兩種方法 (可以用在這個應用程序中的) 用來從 Yahoo Quote 服務器獲取股票信息。第一種方法的格式如下:
http://quote.yahoo.com/d/quotes.csv?s=SUNW&f=slc1wop
如果你在瀏覽器的地址欄輸入這個 URL,你將會看到像圖 1 所示的那些內容。
 圖 2: 獲取股票行情的另一種方法
你可以看到第一種方法的結果是一行文本,解析時會比第二種容易許多,也快許多,因為第二種方法的結果含有大量的文字,包括許多廣告和格式化信息。所以我用第一種方法實現這個關于股票的應用程序,它由兩個類組成:Stock.java 和 StockReader.java。
Stock.java 類
這個類將從 Yahoo Quote 服務器獲得的字符串解析成字段 (例如股票名稱、價格和日期)。示例代碼 3 中展示了一個實現的例子。示例代碼 4 中的 StockReader 類會用到這個工具類。
示例代碼 3:Stock.java
public class Stock {
private static String name, time, price;
// Given a quote from the server, // retrieve the name, price, and date of the stock public static void parse(String data) {
int index = data.indexOf('"'); name = data.substring(++index,(index = data.indexOf('"', index))); index +=3; time = data.substring(index, (index = data.indexOf('-', index))-1); index +=5; price = data.substring(index, (index = data.indexOf('>', index))); }
// Get the name of the stock from public static String getName(String record) { parse(record); return(name); }
// Get the price of the stock from public static String getPrice(String record) { parse(record); return(price); }
// Get the date of the stock public static String getDate(String record) { parse(record);; return time; } }
|
StockReader.java 類
這個類的任務是連接到 Yahoo Quote 服務器,并從服務器上獲取股票行情。它使用 Stock 類解析從服務器返回的字符串。示例代碼 4 是它的一個實現。
示例代碼 4:StockReader.java
import java.io.*; import java.net.*;
public class StockReader { public static void main(String argv[]) throws Exception { String quoteFormat = "&f=slc1wop"; if (argv.length != 1) { System.err.println("Usage: java StockReader <symbol>"); System.exit(1); }
URL url = new URL("http://quote.yahoo.com/d/quotes.csv?"); URLConnection connection = url.openConnection(); connection.setDoOutput(true);
PrintWriter out = new PrintWriter(connection.getOutputStream()); out.println("s=" + argv[0] + quoteFormat); out.close();
BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream())); String line = in.readLine();
/* DEBUG while ((line = in.readLine()) != null) { System.out.println("Got: "+ line); } */ in.close(); System.out.println("Name: "+ Stock.getName(line)); System.out.println("Price: "+ Stock.getPrice(line)); System.out.println("Date: "+ Stock.getDate(line)); } }
|
將數據提交到網頁服務器
在上面的例子中,數據是作為 URL 的一部分被送到服務器的,使用的 GET 方法。現在來看一個使用 POST 方法發送數據的例子。這個例子中,http://www.javacourses.com/cgi-bin 中的 CGI 腳本 (名為 .cgi) 需要 name 和 email 值。如果用戶提交 Sally McDonald 作為 name 值,smc@yahoo.com 作為 email 值,CGI 腳本會獲取輸入并對消息進行解析、解碼,再將提交的內容返回給客戶端。這個 CGI 腳本做事情并不多,但我們要用它來演示如何向服務器提交數據。
還有一點非常重要——請注意使用 POST 方法時,消息內容的類型是 application/x-www-form-urlencoded,這種類型會:
· 指定常規數據編碼 · 將空格轉換為加號 (+) · 將非文本內容轉換成十六進制數后接百分號 (%) 的形式 · 在每個 name=value 對之間放置 & 符號
根據這個編碼規則,消息 (name=Sally McDonald and email=smc@yahoo.com) 在發送給 CGI 腳本之前必須被編碼成:
name=Sally+McDonald&email=smc@yahoo.com
CGI 腳本收到這個已編碼的消息后會對它進行解碼。不過非常幸運,你不必為手工進行編碼操作。你可以使用 java.net.URLEncoder 類來對消息進行編碼,就像下面的例子中那樣。相應地你可以使用 java.net.URLDecoder 來對消息進行解碼。
示例代碼 5 中是這個例子的實現 (使用 HttpURLConnection 類),它展示了如何使用 POST 方法向服務器發送數據。你會看到:
· 為 CGI 腳本打開連接和 I/O 流 · 設置請求方法為 POST · 使用 URLEncoder.encode 方法對消息進行編碼 (URLDecoder.decode 方法可以用于解碼) · 向 CGI 腳本發送已經編碼的消息 · 接收服務器返回的消息并在控制臺打印出來
示例代碼 5:PostExample.java
import java.io.*; import java.net.*;
public class PostExample { public static void main(String[] argv) throws Exception { URL url = new URL("http://www.javacourses.com/cgi-bin/names.cgi"); HttpURLConnection connection = (HttpURLConnection) url.openConnection(); connection.setRequestMethod("POST"); connection.setDoOutput(true); PrintWriter out = new PrintWriter(connection.getOutputStream()); // encode the message String name = "name="+URLEncoder.encode("Qusay Mahmoud", "UTF-8"); String email = "email="+URLEncoder.encode("qmahmoud@javacourses.com", "UTF-8"); // send the encoded message out.println(name+"&"+email); out.close(); BufferedReader in= new BufferedReader(new InputStreamReader(connection.getInputStream())); String line; while ((line = in.readLine()) != null) { System.out.println(line); } in.close(); } }
|
代理服務器和防火墻
如果你使用了防火墻,你就得把代理服務器以及端口號的詳細信息告訴 Java,這樣才能訪問到防火墻外的主機。你可以通過定義一些 HTTP 或者 FTP 屬性來做到:
http.proxyHost (default: ) http.proxyPort (default: 80 if http.proxyHost specified) http.nonProxyHosts (default: )
|
http.proxyHost 和 http.proxyPort 用來指定 HTTP 協議處理器需要使用的代理服務器和端口號。http.nonProxyHosts 用來指定哪些主機是直接連接的 (即不通過代理服務器來連接)。http.nonProxyHosts 屬性的值是一個由 | 分隔開的主機列表,它可以使用正則表達式來表示所匹配的主機,如:*.sfbay.sun.com 將匹配 sfbay 域中的任何主機。
ftp.proxyHost (default: ) ftp.proxyPort (default: 80 if ftp.proxyHost specified) ftp.nonProxyHosts (default: )
|
ftp.proxyHost 和 ftp.proxyPort 用來指定 FTP 協議處理器需要使用的代理服務器和端口號。ftp.nonProxyHosts 用來指定哪些主機是直接聯系的,指定的方法與 http.nonProxyHosts 類似。
你可以在應用程序啟動的時候設置這些屬性:
Prompt> java -Dhttp.proxyHost=HostName -Dhttp.proxyPort=PortNumber yourApp
HTTP 驗證
HTTP 協議提供驗證機制來保護資源。當一個請求要求取得受保護的資源時,網頁服務器回應一個 401 Unauthorized error 錯誤碼。這個回應包含一個指定了驗證方法和領域的 WWW-Authenticate 頭信息。把這個領域想像成一個存儲著用戶名和密碼的數據庫,它將被用來標識受保護資源的有效的用戶。比如,你試著去訪問某個網站上標識為“Personal Files”的資源,服務器響應可能是:WWW-Authenticate: Basic realm="Personal Files" (假設驗證方法是 Basic)。
驗證方法
現在有幾種用于網絡應用的驗證方法,其中最廣泛使用的是基本驗證 (Basic Authentication) 和摘要驗證 (Digest Authentication)。
當用戶想要訪問有限的資源時,使用基本驗證方法的網頁服務器會要求瀏覽器詢顯示一個對話框,并要求用戶輸入用戶名和密碼。如果用戶輸入的用戶名和密碼正確,服務器就允許他訪問這些資源;否則,在接連三次嘗試失敗之后,會顯示一個錯誤消息頁面。這個方法的缺點是用戶名和密碼都是用 Base64 編碼 (全是可讀文本) 之后傳輸過去的。也就是說,這個驗證方法的安全程度只是和 Telnet 一樣,并不是非常安全。
數據驗證方法不會在網絡中傳輸密碼,而是生成一些數字 (根據密碼和其它一些需要的數據產生的) 來代替密碼,而這些數字是經過 MD5 (Message Digest Algorithm) 加密的。生成的值在網絡有隨著服務器需要用來校難密碼的其它信息一起傳輸。這個方法明顯更為安全。
基于表單的驗證方法和基本驗證方法類似,只是服務器使用你自定義的登錄頁面來代替了標準的登錄對話框。
最后,客戶證書驗證使用 SLL (Secure Socket Layer,安全套接層) 和客戶證明。
在 Tomcat 下保護資源
你可以在 tomcat-users.xml 文件中寫一個用戶及其角色的列表。這個文件在 TOMCAT_HOME (你安裝 Tomcat 的目錄) 下的 conf 目錄中。這個文件默認包含了三個用戶 (tomcat、role1、both) 的定義。下面一段 XML 代碼是我添加了兩個新用戶 (qusay 和 reader) 之后的 tomcat-users.xml:
<tomcat-users> <user name="tomcat" password="tomcat" roles="tomcat" /> <user name="role1" password="tomcat" roles="role1" /> <user name="both" password= "tomcat" roles="tomcat,role1" /> <user name="qusay" password="guesswhat" roles="author" /> <user name="reader" password="youguess" roles="reader" /> </tomcat-users>
|
新添加的兩個用戶 (qusay 和 reader) 的 roles 分別設置為 author 和 reader。角色屬性非常重要,因為當你創建安全規則的時候,每個受限制的資源都是與可訪問它的角色相關聯 (稍后你會看到)。
下面做個實驗 (假設你已經安裝并配置好了 Tomcat)。為你期望的頁應用程序建立一個目錄。可以按下列步驟做好準備:
1. 在你安裝了 Tomcat 的目錄下,有一個目錄是 webapps。在這個目錄下建立一個目錄 (如:learn)。 2. 在第一步建立的目錄下建立一個子目錄,命名為 chapter。 3. 在 chapter 目錄中,建立一個 HTML 文件,內容自定,文件名為 index.html。 4. 在第一步建立的目錄下建立一個名為 WEB-INF 的子目錄。 5. 在 WEB-INF 目錄中創建一個名為 web.xml 的文件,該文件內容如下:
6. <?xml version="1.0" encoding="ISO-8859-1"?> 7. 8. <!DOCTYPE web-app 9. PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" 10. "http://java.sun.com/dtd/web-app_2_3.dtd"> 11. 12. <web-app> 13. 14. <description> 15. Learning Web Programming 16. </description> 17. 18. <security-constraint> 19. <web-resource-collection> 20. <web-resource-name> 21. Restricted Area 22. </web-resource-name> 23. <url-pattern>/chapter/*</url-pattern> 24. </web-resource-collection> 25. <auth-constraint> 26. <role-name>tomcat</role-name> 27. <role-name>author</role-name> 28. <role-name>reader</role-name> 29. </auth-constraint> 30. </security-constraint> 31. 32. <login-config> 33. <auth-method>BASIC</auth-method> 34. <realm-name>Authenticate yourself</realm-name> 35. </login-config> 36. </web-app>
|
web.xml 配置描述
web.xml 是描述配置的文件,這里集中說明一下安全相關的配置元素。
<security-constraint>:這個元素限制對一個或者多個資源的訪問,可以在配置信息中出現多次。上面的配置信息中,它限制了 chapter 目錄 (http://localhost:8080/learn/chapter) 下所有資源的訪問。<security-constraint> 包含了下列元素: o <web-resource-collection>:這個元素用于標識你想限制訪問的資源。你可以定義 URL 模式 和 HTTP 方法 (用 <http-method> 元素定義 HTTP 方法)。如果沒有定義 HTTP 方法,那么限制將應用于所有方法。在上面的應用中,我想限制訪問的資源是 http://localhost:8080/learn/chapter/*,也就是 chapter 目錄下的所有文檔。 o <auth-constraint>:這個元素可以訪問上面定義的受限資源的用戶角色。在上面的應用中,tomcat、author 和 erader 這三個角色可以訪問這些資源。
<login-config>:這個元素用于指定驗證方法。它包含下列元素: o <auth-method>:指定驗證方法。它的值可能是下列值集中的一個:BASIC (基本驗證)、DIGEST (摘要驗證)、FORM (基于表單的驗證) 或者 CLIENT-CERT (客戶證書驗證)。 o <realm-name>:如果選用 BASIC 方法進行驗證的時候,標準登錄對話框中的一個描述名稱。
示例
上述配置中使用了 BASIC 驗證方法。下面我們做個實驗:啟動你的 Tomcat 服務器并向它發送到 http://localhost:8080/learn/chapter 的請求。這時候,就會有像圖 3 所示那樣的對話框提示你輸入用戶和密碼:
<BR></DIV><BR><BR>輸入一個用戶及其密碼 (你可以看看 tomcat-users.xml 文件</A>),這個用戶的角色應該在配置 (web.xml) 中存在。如果你輸入的用戶名和密碼正確,你就能訪問到那些資源;否則,你還可以再試兩次。<BR><BR>使用摘要驗證來實驗:<BR><BR>· 關閉你的 Tomcat 服務器</A>。 <BR>· 修改你的配置文件</A> (web.xml),把 BASIC 換成 DIGEST。 <BR>· 重新啟動你的 Tomcat 服務器</A>。 <BR>· 打開一個新的瀏覽器窗口。 <BR>· 在地址欄中輸入 http://localhost:8080/learn/chapter 并回車。 <BR><BR>你會看到類似的對話框。從圖 4 你可以看到,這個登錄對話框是安全的,因為使用了摘要驗證。<BR><BR><BR>
<DIV align=center><IMG src=) 圖 4:HTTP 摘要驗證 (Digest Authentication)
服務器在幕后的回復
當使用基本驗證方法保護資源的時候,服務器發回類似于圖 5 所示的響應信息:
</DIV><BR><BR>如果是使用的摘要驗證方法來保護的資源,服務器</A>發回的響應信息就像圖 6 所示的那樣:<BR><BR><BR>
<DIV align=center><IMG src=) 圖 6:服務器回復 (摘要驗證)
Java 支持 HTTP 驗證
J2SE (1.2 或者更高版本) 通過 Authenticator 類為驗證提供了本地支持。你所要做的只是繼承這個類并實現它的 getPasswordAuthentication 方法。這個方法取得用戶名和密碼并用它們生成一個 PasswordAuthentication 對象返回。完成之后,你還得使用 Authenticator.setDefault 方法注冊你的 Authenticator 實例。現在,只要你想訪問受保護的資源,就會調用 getPasswordAuthentication。Authenticator 類管理著所有低層的詳細資料。它不受 HTTP 的限制,可以應用于所有網絡連接,這不能不說是一個好消息。
示例代碼 6 中是實現 Authenticator 的一個示例。正如你所看到的,在請求驗證的時候,getPasswordAuthentication 方法會彈出一個登錄對話框。
示例代碼 6:AuthImpl.java
import java.net.*; import java.awt.*; import javax.swing.*;
public class AuthImpl extends Authenticator { protected PasswordAuthentication getPasswordAuthentication() { JTextField username = new JTextField(); JTextField password = new JPasswordField(); JPanel panel = new JPanel(new GridLayout(2,2)); panel.add(new JLabel("User Name")); panel.add(username); panel.add(new JLabel("Password") ); panel.add(password); int option= JOptionPane.showConfirmDialog(null, new Object[] {"Site: "+getRequestingHost(), "Realm: "+getRequestingPrompt(),panel}, "Enter Network Password", JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE); if ( option == JOptionPane.OK_OPTION ) { String user = username.getText(); char pass[] = password.getText().toCharArray(); return new PasswordAuthentication(user, pass); } else { return null; } } }
|
示例代碼 7 用來做測試的代碼。我做的第一件事情就是用 Authenticator.setDefault 讓我的 Authenticator 實例開始運行。我不必去解析任何服務器返回的信息以檢查是否需要驗證,因為 Authenticator 類非常聰明,它知道是否需要驗證。
示例代碼 7:BasicReader.java
import java.io.*; import java.net.*;
public class BasicReader { public static void main(String argv[]) throws Exception { Authenticator.setDefault(new AuthImpl()); if (argv.length != 1) { System.err.println("Usage: java BasicReader <site>"); System.exit(1); } URL url = new URL(argv[0]); URLConnection connection = url.openConnection(); BufferedReader in= new BufferedReader(new InputStreamReader(connection.getInputStream()));
String line; StringBuffer sb = new StringBuffer(); while ((line = in.readLine()) != null) { sb.append(line); } in.close(); System.out.println(sb.toString()); System.exit(0); } }
|
運行下面的命令,用 Tomcat 來進行測試:
prompt> java BasicReader http://localhost:8080/learn/chapter
如果你進入的站點需要驗證 (它也這樣做了),那會像圖 7 那樣的對話框就會顯示出來。
主站蜘蛛池模板:
亚洲国产精品18久久久久久|
亚洲乱码卡一卡二卡三|
国产亚洲精品美女|
色吊丝最新永久免费观看网站|
亚洲一级毛片免费在线观看|
黄色成人免费网站|
久久亚洲精品国产精品婷婷|
99在线视频免费观看视频|
亚洲国产精品成人久久久|
久久99国产乱子伦精品免费|
久久久久久亚洲AV无码专区|
久久久精品2019免费观看|
中文字幕亚洲免费无线观看日本|
久久综合给合久久国产免费|
亚洲自偷自拍另类12p|
中文字幕无码免费久久99|
中文字幕精品三区无码亚洲|
免费观看大片毛片|
一级做a爰黑人又硬又粗免费看51社区国产精品视
|
免费看国产一级特黄aa大片|
免费无码AV一区二区|
亚洲人成人网站在线观看|
成人免费无码H在线观看不卡|
亚洲AV无一区二区三区久久|
在线看片免费人成视久网|
亚洲国产夜色在线观看|
毛片免费在线播放|
精品女同一区二区三区免费播放|
久久激情亚洲精品无码?V|
久久免费美女视频|
亚洲男人的天堂久久精品
|
亚洲精品无码永久在线观看|
中文字幕永久免费视频|
亚洲视频免费在线看|
在线免费观看污网站|
yellow视频免费看|
亚洲自偷自偷精品|
无码国模国产在线观看免费|
国产精品免费视频观看拍拍|
亚洲成人网在线观看|
亚洲国产人成精品|
|