HTTP 验证 Tomcat中进行基本验证 (Basic Authentication) 和摘要验证 (Digest Authentication)

时间:2022-01-22 16:20:52

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 所示那样的对话框提示你输入用户和密码:

HTTP 验证 Tomcat中进行基本验证 (Basic Authentication) 和摘要验证 (Digest Authentication)
图 3:HTTP 基本验证 (Basic Authentication)



输入一个用户及其密码 (你可以看看 tomcat-users.xml 文件),这个用户的角色应该在配置 (web.xml) 中存在。如果你输入的用户名和密码正确,你就能访问到那些资源;否则,你还可以再试两次。

使用摘要验证来实验:

· 关闭你的 Tomcat 服务器。 
· 修改你的配置文件 (web.xml),把 BASIC 换成 DIGEST。 
· 重新启动你的 Tomcat 服务器。 
· 打开一个新的浏览器窗口。 
· 在地址栏中输入 http://localhost:8080/learn/chapter 并回车。 

你会看到类似的对话框。从图 4 你可以看到,这个登录对话框是安全的,因为使用了摘要验证。


HTTP 验证 Tomcat中进行基本验证 (Basic Authentication) 和摘要验证 (Digest Authentication)
图 4:HTTP 摘要验证 (Digest Authentication)



服务器在幕后的回复

当使用基本验证方法保护资源的时候,服务器发回类似于图 5 所示的响应信息:

HTTP 验证 Tomcat中进行基本验证 (Basic Authentication) 和摘要验证 (Digest Authentication)
图 5:服务器回复 (基本验证)



如果是使用的摘要验证方法来保护的资源,服务器发回的响应信息就像图 6 所示的那样:


HTTP 验证 Tomcat中进行基本验证 (Basic Authentication) 和摘要验证 (Digest Authentication)
图 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 那样的对话框就会显示出来。

HTTP 验证 Tomcat中进行基本验证 (Basic Authentication) 和摘要验证 (Digest Authentication)
图 7:Java 处理 HTTP 验证



一旦你输入了正确的用户名和密码,服务器就会允许你访问。BasicReader 会读取被请求页面的 HTML 内容并显示在你的控制台窗口。

特别注意:在 Tomcat 4.0 中使用摘要验证时你可能会遇到问题,这是由 J2SE 1.4.0 和 J2SE 1.4.1 的一个 BUG 引起的。不过这个问题已经在 J2SE 1.4.2 中解决了。详情情看这里。 

总结

这篇文章是一篇教程,它介绍了 java.net 包的高层 API。这些 API 使你可以快速简捷地建立有用的网络应用程序,如 StockReader。这里也讨论了 HTTP 验证,并用实例演示了如何使用你自己的验证方案。URL 和 URLConnection 还有一些优势没有在文中提到,它们包括:自动重定向、自动管理保持的连接等。不过现在你已经从文中获得基础知识,可以自己解决这些问题了。