使用Spring RestTemplate进行REST API的基本身份验证

118

我完全不了解RestTemplate和REST API。 我想通过Jira REST API在我的应用程序中检索一些数据,但是返回401未经授权的错误。 在jira rest api文档上找到了一篇文章,但不知道如何将其改写为Java代码,因为示例使用curl命令行方式。 我会感激任何建议或建议如何重写:

curl -D- -X GET -H "Authorization: Basic ZnJlZDpmcmVk" -H "Content-Type: application/json" "http://kelpie9:8081/rest/api/2/issue/QA-31"

使用Spring RestTemplate将其转换为Java代码。其中ZnJlZDpmcmVk是用户名:密码的base64编码字符串。非常感谢。


请参阅https://dev59.com/12ox5IYBdhLWcg3wLhai。 - Raedwald
2
curl支持开箱即用的身份验证,您只需告诉它用户名和密码curl -u fred:fred,无需笨重的手动标头。Spring也是如此。 - divanov
12个回答

189

来自此网站的示例,我认为这是最自然的方法,通过填写头值并将头传递给模板。

这是为了填写头部Authorization

String plainCreds = "willie:p@ssword";
byte[] plainCredsBytes = plainCreds.getBytes();
byte[] base64CredsBytes = Base64.encodeBase64(plainCredsBytes);
String base64Creds = new String(base64CredsBytes);

HttpHeaders headers = new HttpHeaders();
headers.add("Authorization", "Basic " + base64Creds);

这是将标头传递给REST模板的方法:

HttpEntity<String> request = new HttpEntity<String>(headers);
ResponseEntity<Account> response = restTemplate.exchange(url, HttpMethod.GET, request, Account.class);
Account account = response.getBody();

2
谢谢 - 这对我有用。我必须指出,如果您不想使用org.apache.commons.codec.binary.Base64类,并且希望改用android Base64类:import android.util.Base64;,则可以将上面的一行替换为以下内容:byte[] base64CredsBytes = Base64.encode(plainCredsBytes, Base64.DEFAULT); - Simon
@jhadesdev 你好,这个方法在进行 GET 请求时对我有效。但是当进行 POST 请求时会返回 403 错误。你能帮我吗? - Stefano Cazzola
8
在Java 8中,您可以使用Base64.getMimeEncoder().encodeToString()方法进行编码操作。 - Matt Broekhuis
使用spring-web:6.0.10中的HttpHeaders,您还可以编写以下代码: HttpHeaders requestHeaders = new HttpHeaders(); requestHeaders.setBasicAuth(user, password); - CKey

123

您可以使用spring-boot RestTemplateBuilder


@Bean
RestOperations rest(RestTemplateBuilder restTemplateBuilder) {
    return restTemplateBuilder.basicAuthentication("user", "password").build();
}

请参阅文档

(在SB 2.1.0之前,它是#basicAuthorization)


5
谢谢!这是最快、最简单的方法。 - Rajkishan Swami
4
在每个通过RestTemplate发送的请求中添加授权头不是一个好的解决方案。 - attacomsian

50

添加基本的HTTP身份验证到RestTemplate有多种方法。

1. 对于单个请求

try {
    // request url
    String url = "https://jsonplaceholder.typicode.com/posts";

    // create auth credentials
    String authStr = "username:password";
    String base64Creds = Base64.getEncoder().encodeToString(authStr.getBytes());

    // create headers
    HttpHeaders headers = new HttpHeaders();
    headers.add("Authorization", "Basic " + base64Creds);

    // create request
    HttpEntity request = new HttpEntity(headers);

    // make a request
    ResponseEntity<String> response = new RestTemplate().exchange(url, HttpMethod.GET, request, String.class);

    // get JSON response
    String json = response.getBody();

} catch (Exception ex) {
    ex.printStackTrace();
}

如果您使用的是Spring 5.1或更高版本,则不再需要手动设置授权头。请改用headers.setBasicAuth()方法:

// create headers
HttpHeaders headers = new HttpHeaders();
headers.setBasicAuth("username", "password");

2. 对于一组请求

@Service
public class RestService {

    private final RestTemplate restTemplate;

    public RestService(RestTemplateBuilder restTemplateBuilder) {
        this.restTemplate = restTemplateBuilder
                .basicAuthentication("username", "password")
                .build();
    }

   // use `restTemplate` instance here
}

3. 对于每个请求

@Bean
RestOperations restTemplateBuilder(RestTemplateBuilder restTemplateBuilder) {
    return restTemplateBuilder.basicAuthentication("username", "password").build();
}

希望这能有所帮助!


最佳答案。各有所长。 - Rishi
在使用Spring 5.2的时候,我很喜欢看到这句话:“如果你使用的是Spring 5.1或更高版本…”- 是啊,请终于来了! - BAERUS

32

从Spring 5.1开始,您可以使用HttpHeaders.setBasicAuth

创建基本授权头:

String username = "willie";
String password = ":p@ssword";
HttpHeaders headers = new HttpHeaders();
headers.setBasicAuth(username, password);
...other headers goes here...
将头信息传递给RestTemplate:
HttpEntity<String> request = new HttpEntity<String>(headers);
ResponseEntity<Account> response = restTemplate.exchange(url, HttpMethod.GET, request, Account.class);
Account account = response.getBody();

文档: https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/http/HttpHeaders.html#setBasicAuth-java.lang.String-java.lang.String-


27

(也许)最简单的方法,而无需导入spring-boot。

restTemplate.getInterceptors().add(new BasicAuthorizationInterceptor("user", "password"));

5
注意,使用拦截器会导致流无法正常工作。原因如下:在RestTemplate中,exchange()方法调用了doExecute()方法,后者又调用了createRequest()方法和InterceptingHttpAccessor.getRequestFactory()方法。由于RestTemplate继承自InterceptingHttpAccessor,如果存在拦截器,getRequestFactory()方法会返回一个InterceptingClientHttpRequestFactory,该工厂创建InterceptingClientHttpRequest,它们是AbstractBufferingClientHttpRequest的子类,并将输入流转换为字节数组(以便传递给拦截器)。因此,实际上并没有对InputStream进行流式操作。 - mconner
2
该方法已经被弃用,请改用BasicAuthenticationInterceptor。 - 6006604

18

请参考Spring Boot的TestRestTemplate实现,具体来说,请查看以下链接:https://github.com/spring-projects/spring-boot/blob/v1.2.2.RELEASE/spring-boot/src/main/java/org/springframework/boot/test/TestRestTemplate.java

尤其是要注意以下addAuthentication()方法:

private void addAuthentication(String username, String password) {
    if (username == null) {
        return;
    }
    List<ClientHttpRequestInterceptor> interceptors = Collections
            .<ClientHttpRequestInterceptor> singletonList(new BasicAuthorizationInterceptor(
                    username, password));
    setRequestFactory(new InterceptingClientHttpRequestFactory(getRequestFactory(),
            interceptors));
}
同样地,您可以通过继承像TestRestTemplate这样的方式轻松地制作自己的RestTemplate,具体如下所示:

https://github.com/izeye/samples-spring-boot-branches/blob/rest-and-actuator-with-security/src/main/java/samples/springboot/util/BasicAuthRestTemplate.java


the first link leads to 404 - Zarremgregarrok

6

不要像以下这样实例化:

TestRestTemplate restTemplate = new TestRestTemplate();

就像这样做:

TestRestTemplate restTemplate = new TestRestTemplate(user, password);

这对我有效,希望能对你有所帮助!


升级Spring Boot到1.3.x后,TestRestTemplate似乎无法正常工作。 - Vivek Sethi
2
这不是应该用于单元测试而不是发布代码吗? - David Bradley

3
HttpHeaders headers = new HttpHeaders();
        headers.setBasicAuth(username, password);

然后,按照其他人在此处提到的相同步骤继续操作:

HttpEntity<String> request = new HttpEntity<String>(headers);
ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.GET, 
request, String.class);

这似乎只是对这个已有答案的重复。 - undefined

1
使用 setBasicAuth 来定义凭据。
HttpHeaders headers = new HttpHeaders();
headers.setBasicAuth("myUsername", myPassword);

然后按您喜欢的方式创建请求。
示例:
HttpEntity<String> request = new HttpEntity<String>(headers);
ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.GET, 
request, String.class);
String body = response.getBody();

请提供原文以便进行翻译。 - Grigory Kislin

0

按照步骤进行

我在application.Properties文件中添加了客户端凭据,如下所示...

http.basicauth.username = 您的用户名
http.basicauth.password = 您的密码

然后,我创建了一个类,其中包含两个字段,因为我从Application.Properties文件中加载这两个字段:用户名密码。请确保您的类带有@Component注释。

@Value("${http.basicauth.username}")
private String username;

@Value("${http.basicauth.password}")
private String password;

然后,您需要从任何地方自动装配上面的类。

// I'm getting a username and password from application.properties file 
String userCredentials = referenceClassName.getUsername()+":"+referenceClassName.getPassword();
// Encoded User Credentials and Convert it into a String                        
String encodedUserCredentials= Base64.getMimeEncoder().encodeToString(userCredentialsBytes.getBytes());        
headers.set("Authorization", "Basic " +base64UserCredentials);

HttpEntity request = new HttpEntity(headers);
String url = "externalUrl";
// Getting a Json String body
String body = restTemplate.exchange(url,HttpMethod.GET,request,String.class).getBody();

 Note :: For getting an Access Token from String Json body  , That's why  I converted it into a Json Object
 JsonObject tokenJsonObject = new JsonParser().parse(body).getAsJsonObject();
// Getting access token as string from tokenJsonObject
String accessToken = tokenJsonObject.has("access_token") && !tokenJsonObject.get("access_token").isJsonNull() ? tokenJsonObject.get("access_token").getAsString() : "";

如果您有任何疑虑,请在评论中让我知道。希望这对您有所帮助。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接