新闻 | 天津 | 民生 | 广电 | 津抖云 | 微视 | 读图 | 文娱 | 体育 | 图事 | 理论 | 志愿 | 专题 | 工作室 | 不良信息举报
教育 | 健康 | 财经 | 地产 | 天津通 | 旅游 | 时尚 | 购物 | 汽车 | IT | 亲子 | 会计 | 访谈 | 场景秀 | 发布系统

"津云"客户端
  您当前的位置 : 北方网  >  IT浪潮  >  滚动新闻
关键词:

Java SE 6 新特性: HTTP 增强


http://www.enorth.com.cn  2007-08-17 12:55

  引:Java语言从诞生的那天起,就非常注重网络编程方面的应用。随着互联网应用的飞速发展,Java的基础类库也不断地对网络相关的API进行加强和扩展。在Java SE 6 当中,围绕着HTTP协议出现了很多实用的新特性

  概述

  Java语言从诞生的那天起,就非常注重网络编程方面的应用。随着互联网应用的飞速发展,Java的基础类库也不断地对网络相关的API进行加强和扩展。在Java SE 6 当中,围绕着HTTP协议出现了很多实用的新特性:NTLM认证提供了一种Window平台下较为安全的认证机制;JDK当中提供了一个轻量级的HTTP服务器;提供了较为完善的HTTP Cookie管理功能;更为实用的NetworkInterface;DNS域名的国际化支持等等。

  NTLM 认证

  不可避免,网络中有很多资源是被安全域保护起来的。访问这些资源需要对用户的身份进行认证。下面是一个简单的例子:

import java.net.*;

  import java.io.*;

  public class Test {public static void main(String[] args) throws Exception {

  URL url = new URL("http://PROTECTED.com");

  URLConnection connection = url.openConnection();

  InputStream in = connection.getInputStream();

  byte[] data = new byte[1024];

  while(in.read(data)>0)

  {

  //do something for data

  }

  in.close();}}

  当Java程序试图从一个要求认证的网站读取信息的时候,也就是说,从联系于http://Protected.com这个URLConnection的 InputStream中 read数据时,会引发FileNotFoundException。尽管笔者认为,这个Exception的类型与实际错误发生的原因实在是相去甚远;但这个错误确实是由网络认证失败所导致的。

  要解决这个问题,有两种方法:

  其一,是给URLConnection设定一个“Authentication”属性:

String credit = USERNAME + ":" + PASSWORD;

  String encoding = new sun.misc.BASE64Encoder().encode (credit.getBytes());connection.setRequestProperty ("Authorization", "Basic " + encoding);

  这里假设http://PROTECTED.COM使用了基本(Basic)认证类型。

  从上面的例子,我们可以看出,设定Authentication属性还是比较复杂的:用户必须了解认证方式的细节,才能将用户名/密码以一定的规范给出,然后用特定的编码方式加以编码。Java类库有没有提供一个封装了认证细节,只需要给出用户名/密码的工具呢?

  这就是我们要介绍的另一种方法,使用java.net.Authentication类。

  每当遇到网站需要认证的时候,HttpURLConnection都会向Authentication类询问用户名和密码。

  Authentication类不会知道究竟用户应该使用哪个username/password那么用户如何向Authentication类提供自己的用户名和密码呢?

  提供一个继承于Authentication的类,实现getPasswordAuthentication方法,在PasswordAuthentication中给出用户名和密码:

class DefaultAuthenticator extends Authenticator {

  public PasswordAuthentication getPasswordAuthentication () {

  return new PasswordAuthentication ("USER", "PASSWORD".toCharArray());}}

  然后,将它设为默认的(全局)Authentication:

Authenticator.setDefault (new DefaultAuthenticator());

  那么,不同的网站需要不同的用户名/密码又怎么办呢?

  Authentication提供了关于认证发起者的足够多的信息,让继承类根据这些信息进行判断,在getPasswordAuthentication方法中给出了不同的认证信息:

getRequestingHost()

  getRequestingPort() getRequestingPrompt() getRequestingProtocol() getRequestingScheme() getRequestingURL() getRequestingSite() getRequestorType()

  另一件关于Authentication的重要问题是认证类型。不同的认证类型需要Authentication执行不同的协议。至Java SE 6.0为止,Authentication支持的认证方式有:

HTTP Basic authentication

  HTTP Digest authentication NTLM Http SPNEGO Negotiate Kerberos NTLM

  这里我们着重介绍NTLM。

  NTLM是 NT LAN Manager的缩写。早期的SMB协议在网络上明文传输口令,这是很不安全的。微软随后提出了WindowsNT挑战/响应验证机制,即NTLM。

  NTLM协议是这样的:

  ·客户端首先将用户的密码加密成为密码散列;

  ·客户端向服务器发送自己的用户名,这个用户名是用明文直接传输的;

  ·服务器产生一个16位的随机数字发送给客户端,作为一个challenge(挑战) ;

  ·客户端用步骤1得到的密码散列来加密这个challenge ,然后把这个返回给服务器;

  ·服务器把用户名、给客户端的challenge 、客户端返回的response这三个东西,发送域控制器;

  ·域控制器用这个用户名在SAM密码管理库中找到这个用户的密码散列,然后使用这个密码散列来加密challenge;

  ·域控制器比较两次加密的challenge ,如果一样,那么认证成功;

  Java 6 以前的版本,是不支持NTLM认证的。用户若想使用HttpConnection连接到一个使用有Windows域保护的网站时,是无法通过NTLM认证的。另一种方法,是用户自己用Socket这样的底层单元实现整个协议过程,这无疑是十分复杂的。

  终于,Java 6 的Authentication类提供了对NTLM的支持。使用十分方便,就像其他的认证协议一样:

class DefaultAuthenticator extends Authenticator {

  private static String username = "username ";private static String domain = "domain ";private static String password = "password ";

  public PasswordAuthentication getPasswordAuthentication() {

  String usernamewithdomain = domain + "/ "+username;

  return (new PasswordAuthentication(usernamewithdomain, password.toCharArray()));}}

  这里,根据Windows域账户的命名规范,账户名为域名+”/”+域用户名。如果不想每生成PasswordAuthentication时,每次添加域名,可以设定一个系统变量名“http.auth.ntlm.domain“。

  Java 6 中Authentication的另一个特性是认证协商。目前的服务器一般同时提供几种认证协议,根据客户端的不同能力,协商出一种认证方式。比如,IIS服务器会同时提供NTLM with kerberos和 NTLM两种认证方式,当客户端不支持NTLM with kerberos时,执行NTLM认证。

  目前,Authentication的默认协商次序是:

  GSS/SPNEGO -> Digest -> NTLM -> Basic

  那么kerberos的位置究竟在哪里呢?

  事实上,GSS/SPNEGO以 JAAS为基石,而后者实际上就是使用kerberos的。

  轻量级 HTTP 服务器

  Java 6 还提供了一个轻量级的纯Java Http服务器的实现。下面是一个简单的例子:

public static void main(String[] args) throws Exception{

  HttpServerProvider httpServerProvider = HttpServerProvider.provider();InetSocketAddress addr = new InetSocketAddress(7778);HttpServer httpServer = httpServerProvider.createHttpServer(addr, 1);httpServer.createContext("/myapp/", new MyHttpHandler());httpServer.setExecutor(null);httpServer.start();System.out.println("started");}

  static class MyHttpHandler implements HttpHandler{public void handle(HttpExchange httpExchange) throws IOException {

  String response = "Hello world!";

  httpExchange.sendResponseHeaders(200, response.length());

  OutputStream out = httpExchange.getResponseBody();

  out.write(response.getBytes());

  out.close();} }

  然后,在浏览器中访问http://localhost:7778/myapp/,我们得到:


  图一浏览器显示

  首先,HttpServer是从HttpProvider处得到的,这里我们使用了JDK 6 提供的实现。用户也可以自行实现一个HttpProvider和相应的HttpServer实现。

  其次,HttpServer是有上下文(context)的概念的。比如,http://localhost:7778/myapp/中“/myapp/”就是相对于HttpServer Root的上下文。对于每个上下文,都有一个HttpHandler来接收http请求并给出回答。

  最后,在HttpHandler给出具体回答之前,一般先要返回一个Http head。这里使用HttpExchange.sendResponseHeaders(int code, int length)。其中code是 Http响应的返回值,比如那个著名的404。length指的是response的长度,以字节为单位。

编辑:赵国栋  天极Yesky
[进入IT论坛]
请您文明上网、理性发言并遵守相关规定,在注册后发表评论。
 北方网精彩内容推荐
无标题文档
天津民生资讯
天气交通 天津福彩 每月影讯 二手市场
空气质量 天津股票 广播节目 二手房源
失物招领 股市大擂台 天视节目 每日房价
热点专题
北京奥运圣火传递和谐之旅 迎奥运 讲文明 树新风
解放思想 干事创业 科学发展 同在一方热土 共建美好家园
2008天津夏季达沃斯论坛 《今日股市观察》视频
北方网网络相声频道在线收听 2008高考招生简章 复习冲刺
天津自然博物馆馆藏精品展示 2008年天津中考问题解答
带你了解08春夏服饰流行趋势 完美塑身 舞动肚皮舞(视频)
C-NCAP碰撞试验—雪佛兰景程 特殊时期善待自己 孕期检查
热点新闻排行 财经 体育 娱乐 汽车 IT 时尚 健康 教育

Copyright (C) 2000-2021 Enorth.com.cn, Tianjin ENORTH NETNEWS Co.,LTD.All rights reserved
本网站由天津北方网版权所有