第四章 HTTP认证

HttpClient提供对由HTTP标准规范定义的认证模式的完全支持。HttpClient的认证框架可以扩展支持非标准的认证模式,比如NTLM和SPNEGO。

4.1 用户凭证

任何用户身份验证的过程都需要一组可以用于建立用户身份的凭据。用户凭证的最简单的形式可以仅仅是用户名/密码对。UsernamePasswordCredentials代表了一组包含安全规则和明文密码的凭据。这个实现对由HTTP标准规范中定义的标准认证模式是足够的

UsernamePasswordCredentials creds = new UsernamePasswordCredentials("user", "pwd");
System.out.println(creds.getUserPrincipal().getName());
System.out.println(creds.getPassword());

输出内容为:

user
pwd

NTCredentials是微软Windows指定的实现,它包含了除了用户名/密码对外,一组额外的Windows指定的属性,比如用户域名的名字,比如在微软的Windows网络中,相同的用户使用不同设置的认证可以属于不同的域。

NTCredentials creds = new NTCredentials("user", "pwd", "workstation", "domain");
System.out.println(creds.getUserPrincipal().getName());
System.out.println(creds.getPassword());

输出内容为:

DOMAIN/user
pwd

4.2 认证模式

AuthScheme接口代表了抽象的,面向挑战-响应的认证模式。一个认证模式期望支持如下的功能:
  • 解析和处理由目标服务器在对受保护资源请求的响应中发回的挑战。
  • 提供处理挑战的属性:认证模式类型和它的参数,如果可用,比如这个认证模型可应用的领域。
  • 对给定的凭证组和HTTP请求对响应真实认证挑战生成认证字符串。
要注意认证模式可能是有状态的,涉及一系列的挑战-响应交流。HttpClient附带了一些AuthScheme实现:
  • Basic(基本):Basic认证模式定义在RFC 2617中。这个认证模式是不安全的,因为凭据以明文形式传送。尽管它不安全,如果用在和TLS/SSL加密的组合中,Basic认证模式是完全够用的。
  • Digest(摘要):Digest认证模式定义在RFC 2617中。Digest认证模式比Basic有显著的安全提升,对不想通过TLS/SL加密在完全运输安全上开销的应用程序来说也是很好的选择。
  • NTLM:NTLM是一个由微软开发的优化Windows平台的专有认证模式。NTLM被认为是比Digest更安全的模式。这个模式需要外部的NTLM引擎来工作。要获取更多详情请参考包含在HttpClient发布包中的NTLM_SUPPORT.txt文档。

4.3 HTTP认证参数

有一些可以用于定制HTTP认证过程和独立认证模式行为的参数:
  • 'http.protocol.handle-authentication':定义了是否认证应该被自动处理。这个参数期望的得到一个java.lang.Boolean类型的值。如果这个参数没有被设置,HttpClient将会自动处理认证。
  • 'http.auth.credential-charset':定义了当编码用户凭证时使用的字符集。这个参数期望得到一个java.lang.String类型的值。如果这个参数没有被设置,那么就会使用US-ASCII。

4.4 认证模式注册表

HttpClient使用AuthSchemeRegistry类维护一个可用的认证模式的注册表。对于每个默认的下面的模式是注册过的:
  • Basic:基本认证模式
  • Digest:摘要认证模式
请注意NTLM模式没有对每个默认的进行注册。NTLM不能对每个默认开启是应为许可和法律上的原因。要获取更详细的关于如何开启NTLM支持的内容请看这部分。

4.5 凭据提供器

凭据提供器意来维护一组用户凭据,还有能够对特定认证范围生产用户凭据。认证范围包括主机名,端口号,领域名称和认证模式名称。当使用凭据提供器来注册凭据时,我们可以提供一个通配符(任意主机,任意端口,任意领域,任意模式)来替代确定的属性值。如果直接匹配没有发现,凭据提供器期望被用来发现最匹配的特定范围。

HttpClient可以和任意实现了CredentialsProvider接口的凭据提供器的物理代表一同工作。默认的CredentialsProvider实现被称为BasicCredentialsProvider,它是简单的凭借java.util.HashMap的实现。
CredentialsProvider credsProvider = new BasicCredentialsProvider();
credsProvider.setCredentials(
new AuthScope("somehost", AuthScope.ANY_PORT),
new UsernamePasswordCredentials("u1", "p1"));
credsProvider.setCredentials(
new AuthScope("somehost", 8080),
new UsernamePasswordCredentials("u2", "p2"));
credsProvider.setCredentials(
new AuthScope("otherhost", 8080, AuthScope.ANY_REALM, "ntlm"),
new UsernamePasswordCredentials("u3", "p3"));
System.out.println(credsProvider.getCredentials(
new AuthScope("somehost", 80, "realm", "basic")));
System.out.println(credsProvider.getCredentials(
new AuthScope("somehost", 8080, "realm", "basic")));
System.out.println(credsProvider.getCredentials(
new AuthScope("otherhost", 8080, "realm", "basic")));
System.out.println(credsProvider.getCredentials(
new AuthScope("otherhost", 8080, null, "ntlm")));

输出内容为:

[principal: u1]
[principal: u2]
null
[principal: u3]

4.6 HTTP认证和执行上下文

HttpClient依赖于AuthState类来跟踪关于认证过程状态的详细信息。在HTTP请求执行过程中,HttpClient创建2个AuthState的实例:一个对于目标主机认证,另外一个对于代理认证。如果目标服务器或代理需要用户认证,那么各自的AuthState实例将会被在认证处理过程中使用的AuthScope,AuthScheme和Crednetials来填充。AuthState可以被检查来找出请求的认证是什么类型的,是否匹配AuthScheme的实现,是否凭据提供器对给定的认证范围去找用户凭据。

在HTTP请求执行的过程中,HttpClient添加了下列和认证相关的对象到执行上下文中:

  • 'http.authscheme-registry':AuthSchemeRegistry实例代表真实的认证模式注册表。在本地内容中设置的这个属性的值优先于默认的。
  • 'http.auth.credentials-provider':CookieSpec实例代表了真实的凭据提供器。在本地内容中设置的这个属性的值优先于默认的。
  • 'http.auth.target-scope':AuthState实例代表了真实的目标认证状态。在本地内容中设置的这个属性的值优先于默认的。
  • 'http.auth.proxy-scope':AuthState实例代表了真实的代理认证状态。在本地内容中设置的这个属性的值优先于默认的。

本地的HttpContext对象可以用于定制HTTP认证内容,并先于请求执行或在请求被执行之后检查它的状态:

HttpClient httpclient = new DefaultHttpClient();
HttpContext localContext = new BasicHttpContext();
HttpGet httpget = new HttpGet("http://localhost:8080/");
HttpResponse response = httpclient.execute(httpget, localContext);
AuthState proxyAuthState = (AuthState) localContext.getAttribute(
ClientContext.PROXY_AUTH_STATE);
System.out.println("Proxy auth scope: " + proxyAuthState.getAuthScope());
System.out.println("Proxy auth scheme: " + proxyAuthState.getAuthScheme());
System.out.println("Proxy auth credentials: " + proxyAuthState.getCredentials());
AuthState targetAuthState = (AuthState) localContext.getAttribute(
ClientContext.TARGET_AUTH_STATE);
System.out.println("Target auth scope: " + targetAuthState.getAuthScope());
System.out.println("Target auth scheme: " + targetAuthState.getAuthScheme());
System.out.println("Target auth credentials: " + targetAuthState.getCredentials());

4.7 抢占认证

HttpClient不支持开箱的抢占认证,因为滥用或重用不正确的抢占认证可能会导致严重的安全问题,比如将用户凭据以明文形式发送给未认证的第三方。因此,用户期望评估抢占认证和在它们只能应用程序环境内容安全风险潜在的好处,而且要求使用如协议拦截器的标准HttpClient扩展机制添加对抢占认证的支持。

这是一个简单的协议拦截器,如果没有企图认证,来抢先引入BasicScheme的实例到执行上下文中。请注意拦截器必须在标准认证拦截器之前加入到协议处理链中。

HttpRequestInterceptor preemptiveAuth = new HttpRequestInterceptor() {
public void process(final HttpRequest request,
final HttpContext context) throws HttpException, IOException {
AuthState authState = (AuthState) context.getAttribute(
ClientContext.TARGET_AUTH_STATE);
CredentialsProvider credsProvider = (CredentialsProvider) context.getAttribute(ClientContext.CREDS_PROVIDER);
HttpHost targetHost = (HttpHost) context.getAttribute(
ExecutionContext.HTTP_TARGET_HOST);
// 如果没有初始化auth模式
if (authState.getAuthScheme() == null) {
AuthScope authScope = new AuthScope(
targetHost.getHostName(),
targetHost.getPort());
// 获得匹配目标主机的凭据
Credentials creds = credsProvider.getCredentials(authScope);
// 如果发现了,抢先生成BasicScheme
if (creds != null) {
authState.setAuthScheme(new BasicScheme());
authState.setCredentials(creds);
}
}
}
};
DefaultHttpClient httpclient = new DefaultHttpClient();
// 作为第一个拦截器加入到协议链中
httpclient.addRequestInterceptor(preemptiveAuth, 0);

4.8 NTLM 认证

当前HttpClient没有提对开箱的NTLM认证模式的支持也可能永远也不会。这个原因是法律上的而不是技术上的。然而,NTLM认证可以使用外部的NTLM引擎比如JCIFS[http://jcifs.samba.org/]来开启,类库由Samba[http://www.samba.org/]项目开发,作为它们Windows的交互操作程序套装的一部分。要获取详细内容请参考HttpClient发行包中包含的NTLM_SUPPORT.txt文档。

4.8.1 NTLM连接持久化

NTLM认证模式是在计算开销方面昂贵的多的,而且对标准的Basic和Digest模式的性能影响也很大。这很可能是为什么微软选择NTLM认证模式为有状态的主要原因之一。也就是说,一旦认证通过,用户标识是和连接的整个生命周期相关联的。NTLM连接的状态特性使得连接持久化非常复杂,对于明显的原因,持久化NTLM连接不能被使用不同用户标识的用户重用。标准的连接管理器附带HttpClient是完全能够管理状态连接的。而逻辑相关的,使用同一session和执行上下文为了让它们了解到当前的用户标识的请求也是极为重要的。否则,HttpClient将会终止对每个基于NTLM保护资源的HTTP请求创建新的HTTP连接。要获取关于有状态的HTTP连接的详细讨论,请参考这个部分。

因为NTLM连接是有状态的,通常建议使用相对简单的方法触发NTLM认证,比如GET或HEAD,而重用相同的连接来执行代价更大的方法,特别是它们包含请求实体,比如POST或PUT。

DefaultHttpClient httpclient = new DefaultHttpClient();
NTCredentials creds = new NTCredentials("user", "pwd", "myworkstation", "microsoft.com");
httpclient.getCredentialsProvider().setCredentials(AuthScope.ANY, creds);
HttpHost target = new HttpHost("www.microsoft.com", 80, "http");
// 保证相同的内容来用于执行逻辑相关的请求
HttpContext localContext = new BasicHttpContext();
// 首先执行简便的方法。这会触发NTLM认证
HttpGet httpget = new HttpGet("/ntlm-protected/info");
HttpResponse response1 = httpclient.execute(target, httpget, localContext);
HttpEntity entity1 = response1.getEntity();
if (entity1 != null) {
entity1.consumeContent();
}
//之后使用相同的内容(和连接)执行开销大的方法。
HttpPost httppost = new HttpPost("/ntlm-protected/form");
httppost.setEntity(new StringEntity("lots and lots of data"));
HttpResponse response2 = httpclient.execute(target, httppost, localContext);
HttpEntity entity2 = response2.getEntity();
if (entity2 != null) {
entity2.consumeContent();
}

HttpClient 教程 (四)的更多相关文章

  1. CRL快速开发框架系列教程四(删除数据)

    本系列目录 CRL快速开发框架系列教程一(Code First数据表不需再关心) CRL快速开发框架系列教程二(基于Lambda表达式查询) CRL快速开发框架系列教程三(更新数据) CRL快速开发框 ...

  2. 手把手教从零开始在GitHub上使用Hexo搭建博客教程(四)-使用Travis自动部署Hexo(2)

    前言 前面一篇文章介绍了Travis自动部署Hexo的常规使用教程,也是个人比较推荐的方法. 前文最后也提到了在Windows系统中可能会有一些小问题,为了在Windows系统中也可以实现使用Trav ...

  3. C#微信公众号开发系列教程四(接收普通消息)

    微信公众号开发系列教程一(调试环境部署) 微信公众号开发系列教程一(调试环境部署续:vs远程调试) C#微信公众号开发系列教程二(新手接入指南) C#微信公众号开发系列教程三(消息体签名及加解密) C ...

  4. 无废话ExtJs 入门教程四[表单:FormPanel]

    无废话ExtJs 入门教程四[表单:FormPanel] extjs技术交流,欢迎加群(201926085) 继上一节内容,我们在窗体里加了个表单.如下所示代码区的第28行位置,items:form. ...

  5. TFS(Team Foundation Server)敏捷使用教程(四):工作项跟踪(1)

    工作项跟踪(1) 可跟踪性是软件过程的重要能力,TFS主要是以工作项来实现过程的可跟踪性.曾有人问:"你们实际项目里的工作项是怎么样的?能不能让我们看看?"我也一直很好奇别的公司T ...

  6. Android Studio系列教程四--Gradle基础

    Android Studio系列教程四--Gradle基础 2014 年 12 月 18 日 DevTools 本文为个人原创,欢迎转载,但请务必在明显位置注明出处!http://stormzhang ...

  7. Laravel教程 四:数据库和Eloquent

    Laravel教程 四:数据库和Eloquent 此文章为原创文章,未经同意,禁止转载. Eloquent Database 上一篇写了一些Laravel Blade的基本用法和给视图传递变量的几种方 ...

  8. NGUI系列教程四(自定义Atlas,Font)

    今天我们来看一下怎么自定义NGUIAtlas,制作属于自己风格的UI.第一部分:自定义 Atlas1 . 首先我们要准备一些图标素材,也就是我们的UI素材,将其导入到unity工程中.2. 全选我们需 ...

  9. Qt零基础教程(四) QWidget详解篇

    在博客园里面转载我自己写的关于Qt的基础教程,没次写一篇我会在这里更新一下目录: Qt零基础教程(四) QWidget详解(1):创建一个窗口 Qt零基础教程(四) QWidget详解(2):QWid ...

随机推荐

  1. 【BIEE】导出数据报错

    使用BIEE导出数据的时候,发现个问题,导出过程中,报错如下: 问题解决: 找到文件opmn.xml,路径为:/Middleware/instances/instance1/config/OPMN/o ...

  2. doGet和doPost区别

    1,form运行方式 当form框里面的method为get时,执行doGet方法当form框里面的method为post时,执行doPost方法 2,生成方式 get方式有四种:1)直接在URL地址 ...

  3. Redis学习(3)-redis启动

    前端启动 tomcat,redis,mysql的端口号: mysql 3306 tomcat 8088 redis 6379 一,启动redis服务: 例如当前位置在redis安装目录下面: 启动re ...

  4. k8s内核参数调优

    cat /etc/sysctl.conf kernel.core_uses_pid=1 kernel.pid_max=4194303 kernel.ctrl-alt-del=1 # kernel.co ...

  5. PHP-九个非常有用的功能[转]

    1. 函数的任意数目的参数你可能知道PHP允许你定义一个默认参数的函数.但你可能并不知道PHP还允许你定义一个完全任意的参数的函数下面是一个示例向你展示了默认参数的函数:// 两个默认参数的函数fun ...

  6. caffe与MATLAB连接踩的坑

    刚来公司用的服务器,分配给自己账号,安装了caffe,配好了Makefile.config中的MATLAB dir. 之后问题来了 解决方法: 在Makefile里面,大约第410行那一句话CXXFL ...

  7. HawkHost退款流程详解

    http://www.senzw.com/newsfile/2011928115323.htmlHawkhost提供30天退款保证,退款流程也比较简单,下面为大家介绍一下整个退款流程. 首先登录客户中 ...

  8. C#基础 - C# 的 常见概念简述

    在上篇文章中,你跟着我写了一个HelloWorld,本篇中,我们来谈谈一些C#程序中的小概念 1.C# 程序结构 一个 C# 程序主要包括以下部分: 命名空间声明(Namespace declarat ...

  9. Selenium-Grid工作原理

    selenium-grid是由一个hub节点和若干个代理节点组成.hub用来管理各个代理节点的注册和状态信息,并且接受远程客户端代码的请求调用,然后把请求的命令再转发给代理节点来执行.使用seleni ...

  10. http请求No peer certificate的解决方法

    不少同学在做HTTP请求新浪授权或新浪数据的时候会出现 javax.net.ssl.SSLPeerUnverifiedException: No peer certificate的异常.现给出解决方法 ...