添加依赖
pom.xml
com.squareup.okhttp3
okhttp
3.9.1
处理验证
这部分和HTTP AUTH有关.
HTTP AUTH
使用 HTTP AUTH 需要在 server 端配置 http auth 信息, 其过程如下:
- 客户端发送 http 请求 。
- 服务器发现配置了 http auth, 于是检查 request 里面有没有
Authorization
的 http header 。 - 如果有, 则判断
Authorization
里面的内容是否在用户列表里面, Authorization header 的典型数据为Authorization: Basic jdhaHY0=”
, 其中Basic
表示基础认证,jdhaHY0=
是 base64 编码的user:passwd”
字符串。如果没有,或者用户密码不对,则返回 http code 401 页面给客户端.。 - 标准的 http 浏览器在收到401页面之后, 应该弹出一个对话框让用户输入帐号密码; 并在用户点确认的时候再次发出请求, 这次请求里面将带上 Authorization header。
一次典型的访问场景是:
浏览器发送http请求(没有Authorization header)
服务器端返回401页面
浏览器弹出认证对话框
用户输入帐号密码,并点确认
浏览器再次发出http请求(带着Authorization header)
服务器端认证通过,并返回页面
浏览器显示页面
OkHttp 认证
OkHttp 会自动重试未验证的请求. 当响应是401 Not Authorized
时,Authenticator
会被要求提供证书. Authenticator
的实现中需要建立一个新的包含证书的请求. 如果没有证书可用, 返回 null
来跳过尝试.
使用Response.challenges()
来获得任何authentication challenges
的 schemes 和 realms。当完成一个Basic challenge
, 使用Credentials.basic(username, password)
来解码请求头.
- Basic Authentication 认证
private final OkHttpClient client;
public Demo() {
client = new OkHttpClient.Builder()
.authenticator(new Authenticator() {
@Override
public Request authenticate(Route route, Response response) {
System.out.println("Authenticating for response: " + response);
System.out.println("Challenges: " + response.challenges());
String credential = Credentials.basic("jesse", "password1");
return response.request().newBuilder()
.header("Authorization", credential)
.build();
}
})
.build();
}
public void run() throws Exception {
Request request = new Request.Builder()
.url("http://publicobject.com/secrets/hellosecret.txt")
.build();
Response response = client.newCall(request).execute();
if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);
System.out.println(response.body().string());
}
- lambda 表达式如下
client = new OkHttpClient.Builder()
.authenticator((route, response) -> {
System.out.println("Authenticating for response: " + response);
System.out.println("Challenges: " + response.challenges());
String credential = Credentials.basic("jesse", "password1");
return response.request().newBuilder()
.header("Authorization", credential)
.build();
})
.build();
正确授权,打印结果如下
Authenticating for response: Response{protocol=http/1.1, code=401, message=Unauthorized, url=https://publicobject.com/secrets/hellosecret.txt}
Challenges: [Basic realm="OkHttp Secrets" charset="ISO-8859-1"]
authorization:null
@@@@@\
@@@@@@@@
@@@@@@@@@@@@@@@@@@@.
@/ \@@@@@@@@@@@@@@@@.
@ @@@@@@@@@@@@@@@@+
@\ /@@@@@@@@"*@@/^@/
\@@@@@@@@@@/ " "
@@@@@@@@
@@@@@/
:@@@.
.@@@@@@@: +@@ `@@ @@` @@ @@
.@@@@'@@@@: +@@ `@@ @@` @@ @@
@@@ @@@ +@@ `@@ @@` @@ @@
.@@ @@: +@@ @@@ `@@ @@` @@@@@@ @@@@@@ @@;@@@@@
@@@ @@@ +@@ @@@ `@@ @@` @@@@@@ @@@@@@ @@@@@@@@@
@@@ @@@ +@@ @@@ `@@@@@@@@@@` @@ @@ @@@ :@@
@@@ @@@ +@@@@@ `@@@@@@@@@@` @@ @@ @@# @@+
@@@ @@@ +@@@@@+ `@@ @@` @@ @@ @@: @@#
@@: .@@` +@@@+@@ `@@ @@` @@ @@ @@# @@+
@@@. .@@@ +@@ @@@ `@@ @@` @@ @@ @@@ ,@@
@@@@@@@@@ +@@ @@@ `@@ @@` @@@@ @@@@ @@@@#@@@@
@@@@@@@ +@@ #@@ `@@ @@` @@@@: @@@@: @@'@@@@@
@@:
@@:
@@:
耗时:2383
如果输入错误的授权账号,打印结果如下
.... 省略部分 ....
Authenticating for response: Response{protocol=http/1.1, code=401, message=Unauthorized, url=https://publicobject.com/secrets/hellosecret.txt}
Challenges: [Basic realm="OkHttp Secrets" charset="ISO-8859-1"]
authorization:Basic eHg6eHg=
Authenticating for response: Response{protocol=http/1.1, code=401, message=Unauthorized, url=https://publicobject.com/secrets/hellosecret.txt}
Challenges: [Basic realm="OkHttp Secrets" charset="ISO-8859-1"]
authorization:Basic eHg6eHg=
java.net.ProtocolException: Too many follow-up requests: 21
at okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.java:171)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:121)
at okhttp3.RealCall.getResponseWithInterceptorChain(RealCall.java:200)
at okhttp3.RealCall.execute(RealCall.java:77)
at com.tingfeng.guide.Test.run(Test.java:40)
at com.tingfeng.guide.Test.main(Test.java:49)
- 为避免当验证不工作而导致许多重试,你可以返回null放弃,例如:当这些确切的证书已经尝试访问过时你可能想跳过重试:
client = new OkHttpClient.Builder()
.authenticator((route, response) -> {
System.out.println("Authenticating for response: " + response);
System.out.println("Challenges: " + response.challenges());
String credential = Credentials.basic("xx", "xx");
if (credential.equals(response.request().header("Authorization"))) {
System.out.println("验证失败,返回null");
return null;
}
return response.request().newBuilder()
.header("Authorization", credential)
.build();
})
.build();
打印结果如下,这种方式会在第三次认证失败返回null
Authenticating for response: Response{protocol=http/1.1, code=401, message=Unauthorized, url=https://publicobject.com/secrets/hellosecret.txt}
Challenges: [Basic realm="OkHttp Secrets" charset="ISO-8859-1"]
authorization:null
Authenticating for response: Response{protocol=http/1.1, code=401, message=Unauthorized, url=https://publicobject.com/secrets/hellosecret.txt}
Challenges: [Basic realm="OkHttp Secrets" charset="ISO-8859-1"]
authorization:Basic eHg6eHg=
认证失败,返回null
java.io.IOException: Unexpected code Response{protocol=http/1.1, code=401, message=Unauthorized, url=https://publicobject.com/secrets/hellosecret.txt}
at com.tingfeng.guide.Test.run(Test.java:41)
at com.tingfeng.guide.Test.main(Test.java:49)
- 当你设置一个应用程序定义的限制时你也可以跳过重试
client = new OkHttpClient.Builder()
.authenticator((route, response) -> {
System.out.println("Authenticating for response: " + response);
System.out.println("Challenges: " + response.challenges());
String credential = Credentials.basic("xx", "xx");
String authorization = response.request().header("Authorization");
System.out.println("authorization:"+ authorization);
// 第5次认证失败返回null
if (responseCount(response) >= 5) {
System.out.println("认证失败,返回null");
return null; // If we've failed 5 times, give up.
}
return response.request().newBuilder()
.header("Authorization", credential)
.build();
})
.build();
这上面的代码依赖于 responseCount()
方法:
private int responseCount(Response response) {
int result = 1;
while ((response = response.priorResponse()) != null) {
result++;
}
return result;
}
Bearer Token认证
使用 Header 传递 Authorization 认证参数
public static final MediaType JSON = MediaType.parse("application/json; charset=utf-8");
OkHttpClient client = new OkHttpClient();
String post(String url, String json) throws IOException {
RequestBody body = RequestBody.create(JSON, json);
Request request = new Request.Builder()
.url(url)
.addHeader("Authorization","Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ0aW5nZmVuZyIsInJvbGVzIjpbIk1FTUJFUiJdLCJpYXQiOjE1MjM0Mzg4ODYsImV4cCI6MTUyMzQ0MjQzMH0.5oQU1HUekYxP6BE534Vek_O6ZXhwPbUXQJuBB_da8r8")
.post(body)
.build();
try (Response response = client.newCall(request).execute()) {
return response.body().string();
}
}
测试
public static void main(String[] args) throws IOException {
PostExample example = new PostExample();
String json = "{\"username\":\"tingfeng\",\"password\":\"tingfeng\"}";
String response = example.post("http://localhost:8080/secure/user/roles", json);
System.out.println(response);
}
转载自 http://www.ibloger.net/article/3094.html