我只是记录用户,在首选项中存储一些关键身份验证响应数据,并尝试在需要cookie的情况下执行后续HTTP GET调用。以下设置产生401未经授权的响应,这使我相信我正在不正确地处理Retrofit(v2.1.0)拦截器中的cookie。如何使用Retrofit拦截器发送cookie,然后允许我进行后续API调用?
示例摘自:https://gist.github.com/nikhiljha/52d45ca69a8415c6990d2a63f61184ff
认证
OkHttpClient client = new OkHttpClient();
OkHttpClient.Builder builder = new OkHttpClient.Builder();
builder.addInterceptor(new AddCookiesInterceptor(context)); // VERY VERY IMPORTANT
builder.addInterceptor(new ReceivedCookiesInterceptor(context)); // VERY VERY IMPORTANT
client = builder.build();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(Constants.BASE_URL)
.client(client) // VERY VERY IMPORTANT
.addConverterFactory(GsonConverterFactory.create())
.build();
final MembershipApi service = retrofit.create(MembershipApi.class);
UserCredentials userCredentials = new UserCredentials();
userCredentials.setUsername(mUsername);
userCredentials.setPassword(mPassword);
userCredentials.setIncludeExchangeToken(true);
userCredentials.setUserType("Member");
userCredentials.setIncludeMemberConfig(true);
Call<UserData> userDataCall = service.authenticateUsername(userCredentials);
userDataCall.enqueue(new Callback<UserData>() {
@Override
public void onResponse(Call<UserData> call, Response<UserData> response) {
int statusCode = response.code();
String message = response.message();
UserData userData = response.body();
pbProgress.setVisibility(View.GONE);
Timber.v("onResponse " + statusCode);
Timber.v("onResponse " + message);
if (statusCode == 200) {
// Create user login session
Timber.v("login successful");
try {
// session is simply a helper class that stores key authentication response data in preferences
session.createUserLoginSession(
userData.getMemberID(),
userData.getClientID(),
userData.getFullName(),
userData.getMemberConfig().getClientNameMobile(),
userData.getExchangeToken());
} catch (Exception e) {
e.printStackTrace();
}
// launch feed activity
goFeed();
} else {
Timber.v("login failure");
Toast.makeText(getApplicationContext(), getResources().getString(R.string.text_login_failed), Toast.LENGTH_SHORT).show();
}
}
@Override
public void onFailure(Call<UserData> call, Throwable t) {
pbProgress.setVisibility(View.GONE);
Timber.v("onFailure: " + t.getMessage());
}
});
后续GET检索Feed:
OkHttpClient client = new OkHttpClient();
OkHttpClient.Builder builder = new OkHttpClient.Builder();
builder.addInterceptor(new AddCookiesInterceptor(this)); // VERY VERY IMPORTANT
builder.addInterceptor(new ReceivedCookiesInterceptor(this)); // VERY VERY IMPORTANT
client = builder.build();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(Constants.BASE_URL)
.client(client) // VERY VERY IMPORTANT
.addConverterFactory(GsonConverterFactory.create())
.build();
MembershipApi service = retrofit.create(MembershipApi.class);
Call<FeedData> userDataCall = service.getFeed(Integer.parseInt(session.getClientId()), Integer.parseInt(session.getKeyMemberId()),
"All", 10, 1, 0, 0, "Android" );
userDataCall.enqueue(new Callback<FeedData>() {
@Override
public void onResponse(Call<FeedData> call, Response<FeedData> response) {
int statusCode = response.code();
String message = response.message();
Timber.v("onResponse " + statusCode);
Timber.v("onResponse " + message);
if (statusCode == 200) {
// Create user login session
Timber.v("feed successful");
} else {
Timber.v("feed failure");
Toast.makeText(getApplicationContext(), getResources().getString(R.string.text_login_failed), Toast.LENGTH_SHORT).show();
}
}
@Override
public void onFailure(Call<FeedData> call, Throwable t) {
Timber.v("onFailure: " + t.getMessage());
}
});
ReceivedCookiesInterceptor.java:
import android.content.Context;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import java.io.IOException;
import java.util.HashSet;
import okhttp3.Interceptor;
import okhttp3.Response;
public class ReceivedCookiesInterceptor implements Interceptor {
private Context context;
public ReceivedCookiesInterceptor(Context context) {
this.context = context;
} // AddCookiesInterceptor()
@Override
public Response intercept(Chain chain) throws IOException {
Response originalResponse = chain.proceed(chain.request());
if (!originalResponse.headers("Set-Cookie").isEmpty()) {
HashSet<String> cookies = (HashSet<String>) PreferenceManager.getDefaultSharedPreferences(context).getStringSet("PREF_COOKIES", new HashSet<String>());
for (String header : originalResponse.headers("Set-Cookie")) {
cookies.add(header);
}
SharedPreferences.Editor memes = PreferenceManager.getDefaultSharedPreferences(context).edit();
memes.putStringSet("PREF_COOKIES", cookies).apply();
memes.commit();
}
return originalResponse;
}
}
AddCookiesInterceptor
import android.content.Context;
import android.preference.PreferenceManager;
import android.util.Log;
import java.io.IOException;
import java.util.HashSet;
import okhttp3.Interceptor;
import okhttp3.Request;
import okhttp3.Response;
/**
* This interceptor put all the Cookies in Preferences in the Request.
* Your implementation on how to get the Preferences may vary, but this
* will work 99% of the time
*/
public class AddCookiesInterceptor implements Interceptor {
public static final String PREF_COOKIES = "PREF_COOKIES";
// We're storing our stuff in a database made just for cookies called PREF_COOKIES.
// I recommend you do this, and don't change this default value.
private Context context;
public AddCookiesInterceptor(Context context) {
this.context = context;
}
@Override
public Response intercept(Interceptor.Chain chain) throws IOException {
Request.Builder builder = chain.request().newBuilder();
HashSet<String> preferences = (HashSet<String>) PreferenceManager.getDefaultSharedPreferences(context).getStringSet(PREF_COOKIES, new HashSet<String>());
// Use the following if you need everything in one line.
// Some APIs die if you do it differently.
//String cookiestring = "";
//for (String cookie : preferences) {
// String[] parser = cookie.split(";");
// cookiestring = cookiestring + parser[0] + "; ";
//}
//builder.addHeader("Cookie", cookiestring);
for (String cookie : preferences) {
builder.addHeader("Cookie", cookie);
}
return chain.proceed(builder.build());
}
}