| 
 
  当您用喜好的浏览器在网上冲浪时,您会遇到要求代理服务器认证或 HTTP 服务器认证的 URL,并会出现您再熟悉不过的窗口要求您输入用户名及口令: 
 从浏览器访问一个诸如 http://www.lombard.com/cgi-bin/Quotes/quote 这样的 URL 不成问题,因为您自己可以提供用户名和口令。但是当您试图通过 Java 程序从与此 URL 相关的 InputStream 中读取数据时,该 Java 程序就会发出 FileNotFoundException 异常。 
   
 在 Java 1.0 或 1.1 中,您可以通过在连接时记入 (post) 适当的认证字符串来避免这种情况,但这种方法仅在您事先知道该 URL 是受保护的时才奏效。(Authorization: Basic username:password,其中基本认证域是以 base 64 编码的。)如果您事先没有预见到文档是受保护的,则您甚至无法读取文件内容。(有关用 Java 1.1 applet 或应用程序访问口令保护的 URL 的解决方案,请参阅“Java 技巧 47:再谈 URL 认证”。值得庆幸的是,Java 1.2 在 java.net 包中添加了一个 Authenticator 类,这使得访问口令保护的 URL 变得极为容易。 
 现在,对于 Java 1.2,您只需用 Authenticator.setDefault() 安装一个 Authenticator。这样,当需要认证时,已安装的 Authenticator 的 getPasswordAuthentication() 方法就会被调用,然后您就可以用适当的用户名和口令来设置 PasswordAuthentication 实例。就这么简单。 
 所需步骤如下所示。 
 第一步:安装 Authenticator 
 Authenticator.setDefault (new MyAuthenticator ());
 
 第二步:创建 Authenticator 的子类 
 class MyAuthenticator extends Authenticator {   protected PasswordAuthentication getPasswordAuthentication() {     return new PasswordAuthentication ("username", "password");   } }
 
 以下程序完整地显示了这种行为,它提供了自己的认证提示对话框。 
 import java.io.*; import java.net.*;  import java.awt.*; import java.awt.event.*;
  public class URLPassword extends Frame {
    private TextField tf = new TextField();   private TextArea ta = new TextArea();
    public URLPassword() {
      super ("URL Password");
      // 安装 Authenticator     Authenticator.setDefault (new MyAuthenticator ());
      // 设置屏幕     add (tf, BorderLayout.NORTH);     ta.setEditable(false);     add (ta, BorderLayout.CENTER);     tf.addActionListener (new ActionListener() {       public void actionPerformed (ActionEvent e) {         String s = tf.getText();         if (s.length() != 0)           ta.setText (fetchURL (s));       }     });     addWindowListener (new WindowAdapter() {       public void windowClosing (WindowEvent e) {         dispose();         System.exit(0);       }     });   }
    private String fetchURL (String urlString) {     StringWriter sw = new StringWriter();     PrintWriter pw = new PrintWriter(sw);
      try {       URL url = new URL (urlString);       InputStream content = (InputStream)url.getContent();       BufferedReader in =          new BufferedReader (new InputStreamReader (content));       String line;       while ((line = in.readLine()) != null) {         pw.println (line);       }     } catch (MalformedURLException e) {       pw.println ("Invalid URL");     } catch (IOException e) {       pw.println ("Error reading URL");     }     return sw.toString();   }
    public static void main (String args[]) {     Frame f = new URLPassword();     f.setSize(300, 300);     f.setVisible (true);   }
    class MyAuthenticator extends Authenticator {     protected PasswordAuthentication getPasswordAuthentication() {       final Dialog jd = new Dialog (URLPassword.this, "Enter password", true);       jd.setLayout (new GridLayout (0, 1));       Label jl = new Label (getRequestingPrompt());       jd.add (jl);       TextField username = new TextField();       username.setBackground (Color.lightGray);       jd.add (username);       TextField password = new TextField();       password.setEchoChar ('*');       password.setBackground (Color.lightGray);       jd.add (password);       Button jb = new Button ("OK");       jd.add (jb);       jb.addActionListener (new ActionListener() {         public void actionPerformed (ActionEvent e) {           jd.dispose();         }       });       jd.pack();       jd.setVisible(true);       return new PasswordAuthentication (username.getText(), password.getText());     }   } }
 
 
 
|  后续技巧!    |  
| 来自 Luis Blanco Gomez 
 代码的第 85 行(MyAuthenticator 类的返回参数)显示一个错误: 
 return new PasswordAuthentication (username.getText(), password.getText());
 
 编译器将报错: 
 URLPass.java:88: Incompatible type for constructor. Can't convert java.lang.String to char[].     return new PasswordAuthentication ( username.getText(), password.getText());
 
 为修正此错误,您必须声明一个 String 变量来存储 password.getText();例如,"String pass= password.getText();",并将返回行改为: 
 return new PasswordAuthentication ( username.getText(), pass.toCharArray());
 
  |    |   为了测试这个程序,必须找出一个您知道其用户名和口令的 URL。就 Discover Brokerage Direct 而言,任何人都可以在 registration desk 获得一个免费口令。接下来,用 URL http://www.lombard.com/cgi-bin/Quotes/quote 来测试该程序。 
有几点值得一提:不可信的 applet 可在 appletviewer 中安装一个缺省的 Authenticator。HotJava、Navigator 和 Internet Explorer 会怎么做尚不清楚。如果您没有必要的权限便试图更改 authenticator,该程序就会发出一个 AccessControlException 异常。 
 提交您喜好的 Java 技巧 每篇技巧都将提供有关有用的技巧和窍门的几则简短信息,以帮助您改进 Java 代码。我们将探究这一出色技术的诸多方面,每次讨论一个 Java bean。 
 我们也希望将您的 Java 技巧刊登在以后的 Java world 上。赶快将您最棒的技巧和窍门写出来并发送到 javatips@javaworld.com。您可能会发现自己成了 JavaWorld 的一名作者,因为您的有益提示可能成为下一篇 Java 技巧! 
 
 
  
  
  |