RestTemplate进阶:打开Basic Authorization的正确zishi,你知道吗<( ̄︶ ̄)↗[GO!]

2023-03-07 14:47:28 浏览数 (1)

生活就是练习.柬埔寨

原文链接:https://www.baeldung.com/how-to-use-resttemplate-with-basic-authentication-in-spring

作者: Eugen Paraschiv

译者: helloworldtang

目录

  • 1. 概览
  • 2. 在Spring中配置RestTemplate
  • 3. 手动管理 Authorization HTTP头
  • 4. 自动管理 Authorization HTTP头
  • 5. Maven依赖
  • 6.总结

1. 概览

本文将展示如何使用Spring RestTemplate消费一个需要 Basic身份认证的RESTful服务

一旦为RestTemplate配置了用于 Basic身份认证的HTTP头,每个请求都会携带用于身份认证的完整凭证。凭证信息将按照 Basic身份认证规范进行编码并存放到一个名为Authorization的HTTP头中。一个Authorization HTTP头会长这个样子:

代码语言:javascript复制
Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==

2. 配置RestTemplate

通过简单地将 RestTemplate类声明为一个 bean,就可以将其注入到Spring上下文;然而,要注入一个携带 Basic身份认证信息的 RestTemplate,就需要一些额外的自定义配置,因此我们将使用Spring FactoryBean来实现更大的灵活性,而不是直接声明 bean。这个工厂类将在初始化时创建和配置 RestTemplate

代码语言:javascript复制
@Component
public class RestTemplateFactory
  implements FactoryBean<RestTemplate>, InitializingBean {

    private RestTemplate restTemplate;

    public RestTemplate getObject() {
        return restTemplate;
    }
    public Class<RestTemplate> getObjectType() {
        return RestTemplate.class;
    }
    public boolean isSingleton() {
        return true;
    }

    public void afterPropertiesSet() {
        HttpHost host = new HttpHost("localhost", 8082, "http");
        restTemplate = new RestTemplate(
          new HttpComponentsClientHttpRequestFactoryBasicAuth(host));
    }
}

hostport值应该依赖于环境——即开发环境、测试环境、预发布环境、生产环境下的值是不同的。在Spring中,可以通过 properties文件来管理这些值。

3.手动管理AuthorizationHTTP头

对于 Basic身份认证来说,创建Authorization头也比较简单,即只需几行代码就可以完成:

代码语言:javascript复制
    HttpHeaders createHeaders(String username, String password) {
        return new HttpHeaders() {
            {
                String auth = username   ":"   password;
                byte[] originAuth = auth.getBytes(Charset.forName("US-ASCII"));
                byte[] encodedAuth = Base64.encodeBase64(originAuth);
                String authHeader = "Basic "   new String(encodedAuth);
                set("Authorization", authHeader);
            }
        };
    }

那么,发送请求也变得同样简单:

代码语言:javascript复制
restTemplate.exchange
 (uri, HttpMethod.POST, new HttpEntity<T>(createHeaders(username, password)), clazz);

4.自动管理AuthorizationHTTP头

Spring 3.0、3.1和现在的4.x都对Apache HTTP库有很好的支持:

  • 在Spring 3.0中,CommonsClientHttpRequestFactory集成了现在已经停止更新的HttpClient 3.x
  • 在Spring 3.1中,通过HttpComponentsClientHttpRequestFactory引入了对HttpClient 4.x的支持(在JIRA SPR-6180中添加的支持)
  • 在Spring 4.0中,通过HttpComponentsAsyncClientHttpRequestFactory引入对异步请求的支持

现在,咱们开始使用HttpClient 4和Spring 4来配置一些东西。

到目前为止,RestTemplate需要一个HttpRequestFactory——一个支持 Basic身份认证的工厂类。然而,直接使用现有的HttpComponentsClientHttpRequestFactory是困难的,因为RestTemplate的架构在设计时并没有很好的支持 HttpContext——这是“拼图”的重要组成部分。 因此,我们需要继承 HttpComponentsClientHttpRequestFactory并覆盖 createHttpContext方法:

代码语言:javascript复制
public class HttpComponentsClientHttpRequestFactoryBasicAuth 
  extends HttpComponentsClientHttpRequestFactory {

    HttpHost host;

    public HttpComponentsClientHttpRequestFactoryBasicAuth(HttpHost host) {
        super();
        this.host = host;
    }

    protected HttpContext createHttpContext(HttpMethod httpMethod, URI uri) {
        return createHttpContext();
    }

    private HttpContext createHttpContext() {
        AuthCache authCache = new BasicAuthCache();

        BasicScheme basicAuth = new BasicScheme();
        authCache.put(host, basicAuth);

        BasicHttpContext localcontext = new BasicHttpContext();
        localcontext.setAttribute(HttpClientContext.AUTH_CACHE, authCache);
        return localcontext;
    }
}

如上所示——在创建HttpContext时,就内置了Basic身份认证信息。这你也看到了,使用HttpClient 4.x进行抢占式Basic身份认证是有点负担:缓存身份认证信息,并且建立这个身份认证缓存的过程也必须手动配置,并且非常不直观的。

万事俱备—— RestTemplate现在可以通过添加BasicAuthorizationInterceptor来支持Basic身份认证;

代码语言:javascript复制
restTemplate.getInterceptors().add(
  new BasicAuthorizationInterceptor("username", "password"));

那么,具体的请求代码如下所示:

代码语言:javascript复制
restTemplate.exchange(
  "http://localhost:8082/spring-security-rest-basic-auth/api/foos/1", 
  HttpMethod.GET, null, Foo.class);

如果想了解如何保护REST服务的更多信息,请移步这篇。

5. Maven依赖

下面的Maven依赖项对于RestTemplate本身和HttpClient库都是必需的:

代码语言:javascript复制
<dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-webmvc</artifactId>
   <version>5.0.6.RELEASE</version>
</dependency>

<dependency>
   <groupId>org.apache.httpcomponents</groupId>
   <artifactId>httpclient</artifactId>
   <version>4.5.3</version>
</dependency>

另外,如果通过手动生成Authorization HTTP头,也可以使用下面这个库来完成编码操作:

代码语言:javascript复制
<dependency>
   <groupId>commons-codec</groupId>
   <artifactId>commons-codec</artifactId>
   <version>1.10</version>
</dependency>

你可以在Maven仓库发现最新的版本。

6. 总结

尽管Apache HttpClient的3.x开发分支已经停止更新,并且Spring对这个版本的支持也已经被完全废弃了,但是在 RestTemplate和安全性上找到的大部分信息仍然不能解释当前HttpClient 4.x发行版中的一些设计。本文尝试通过循序渐进的方式来解读如何使用RestTemplate来配置 Basic身份认证以及如何使用它来消费一个受保护的REST API来改变这种情况。

如果想写出更好的代码,或者想了解HTTP客户端以及用到的RESTful服务的实现,请查看Github上的项目。 这是一个基于Maven的项目,因此很容易导入和运行。

0 人点赞