[英]Oauth2 refresh with Dagger2 Android
I'm trying to implement Oauth2 login with Dagger2.我正在尝试使用 Dagger2 实现 Oauth2 登录。 Once the access_token gets expired, I have successfully generated new access_token through the refresh_token, but the Authenticator goes on infinite loop once refresh_token is also expired.一旦 access_token 过期,我已经通过 refresh_token 成功生成了新的 access_token,但是一旦 refresh_token 也过期,Authenticator 就会进入无限循环。
This is my Network module, where I defined, Authenticator and Interceptor in OkHttp Client这是我的网络模块,我在 OkHttp Client 中定义了 Authenticator 和 Interceptor
@Module
public class NetworkModule
{
@Provides
@Singleton
OkHttpClient provideOkHttpClient(TokenAuthenticator tokenAuthenticator, TokenInceptor tokenInceptor, SharedManager sharedManager)
{
HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
logging.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
// adding socket time for read/write/reconnect
httpClient.connectTimeout(30, TimeUnit.SECONDS);
httpClient.writeTimeout(30, TimeUnit.SECONDS);
httpClient.readTimeout(30, TimeUnit.SECONDS);
// setting the accept type of the request to application/json
httpClient.addNetworkInterceptor(new Interceptor()
{
@Override
public Response intercept(Chain chain) throws IOException {
Request.Builder requestBuilder = chain.request().newBuilder();
requestBuilder.header("Accept", "application/json");
return chain.proceed(requestBuilder.build());
}
});
httpClient.addInterceptor(logging).addInterceptor(tokenInceptor);
httpClient.authenticator(tokenAuthenticator);
return httpClient.build();
}
}
@Provides
Retrofit provideRetrofit(OkHttpClient okHttpClient){
return new Retrofit.Builder()
.baseUrl(ApiConstants.API_BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.client(okHttpClient)
.build();
}
@Provides
@Singleton
ApiService provideApiService(Retrofit retrofit, TokenService apiServiceHolder)
{
ApiService apiService = retrofit.create(ApiService.class);
apiServiceHolder.setApiService(apiService);
return apiService;
}
@Provides
@Singleton
public SharedPreferences providePreferences(Application application)
{
return application.getSharedPreferences(Constants.APP_PREFERENCES, Context.MODE_PRIVATE);
}
@Provides
@Singleton
public SharedManager provideSharedManager(SharedPreferences sharedPreferences)
{
return new SharedManager(sharedPreferences);
}
@Provides
@Singleton
public TokenAuthenticator tokenAuthenticator(TokenService tokenService, SharedManager sharedManager)
{
return new TokenAuthenticator(tokenService, sharedManager);
}
@Provides
@Singleton
public TokenInceptor tokenInceptor(SharedManager sharedManager)
{
return new TokenInceptor(sharedManager);
}
@Provides
@Singleton
public TokenService apiServiceHolder()
{
return new TokenService();
}
}
Here's the Interceptor这是拦截器
@Singleton
public class TokenInceptor implements Interceptor
{
SharedManager sharedManager;
@Inject
public TokenInceptor(SharedManager sharedManager)
{
this.sharedManager = sharedManager;
}
@Override
public Response intercept(Chain chain) throws IOException
{
Request request = chain.request();
// we don't need header in login/register so, we remove the header from these api request endpoints
if(request.url().encodedPath().contains("/token/client") && request.method().equalsIgnoreCase("POST"))
{
return chain.proceed(request);
}
// then we add the authenticator to other api requests
HttpUrl url = request.url();
Request.Builder urlBuilder = request.newBuilder().addHeader(ApiConstants.AUTHORIZATION, sharedManager.getBearer()).url(url);
Request apiRequest = urlBuilder.build();
return chain.proceed(apiRequest);
}
}
Here's the Authenticator这是身份验证器
@Singleton
public class TokenAuthenticator implements Authenticator
{
private SharedManager sharedManager;
private TokenService tokenService;
@Inject
public TokenAuthenticator(@NonNull TokenService apiServiceHolder, SharedManager sharedManager)
{
this.tokenService = apiServiceHolder;
this.sharedManager = sharedManager;
}
@Nullable
@Override
public Request authenticate(Route route, Response response) throws IOException
{
if(!response.request().header(ApiConstants.AUTHORIZATION).equals(sharedManager.getBearer()))
{
return null;
}
retrofit2.Response<TokenResponse> tokenResponse = tokenService.getApiService().refreshToken(sharedManager.getRefresh()).execute();
TokenResponse responseData = tokenResponse.body();
if(tokenResponse.isSuccessful() && responseData!= null)
{
TokenResponse responseRequest = (TokenResponse) tokenResponse.body();
String new_token = responseRequest.getAccess();
sharedManager.saveAccessToken(new_token);
return response.request().newBuilder().header(ApiConstants.AUTHORIZATION,sharedManager.getBearer()).build();
}
else
{
// As per my assumption, the refresh token might expire here
Log.e("refresh_token","expired");
}
return null;
}
}
Here's the TokenService class这是 TokenService class
public class TokenService
{
ApiService apiService = null;
@Nullable
public ApiService getApiService() {
return apiService;
}
public void setApiService(ApiService apiService) {
this.apiService = apiService;
}
}
Here's SharedManager class这是 SharedManager class
public class SharedManager
{
private SharedPreferences sharedPreferences;
@Inject
public SharedManager(SharedPreferences sharedPreferences)
{this.sharedPreferences = sharedPreferences;};
public void saveAccessToken(String token)
{
sharedPreferences.edit().putString(ApiConstants.ACCESS_TOKEN, token).commit();
}
public void saveRefreshToken(String token)
{
sharedPreferences.edit().putString(ApiConstants.REFRESH, token).commit();
}
public String getAccessToken()
{
return sharedPreferences.getString(ApiConstants.ACCESS_TOKEN, "");
}
public String getRefresh()
{
return sharedPreferences.getString(ApiConstants.REFRESH, "");
}
public String getBearer()
{
return "Bearer "+getAccessToken();
}
public void clearAll()
{
sharedPreferences.edit().clear().commit();
}
}
Here's ApiService interface这是 ApiService 接口
public interface ApiService
{
// client login
@POST("token/client")
@FormUrlEncoded
Call<ResponseBody> loginUser(@Field("email") String email,
@Field("password") String password);
// method for refresh token
@POST("token/refresh")
@FormUrlEncoded
Call<TokenResponse> refreshToken(@Field("refresh") String refresh);
// get agent
@GET("agent")
Call<ResponseBody> getAgentTour();
}
Can anyone trace out the faults in the code here?任何人都可以在这里找出代码中的错误吗? The code structure changed while posting in stack.在堆栈中发布时代码结构发生了变化。
A standard refresh token grant message will return an error code of invalid_grant when the refresh token finally expires.当刷新令牌最终到期时,标准的刷新令牌授予消息将返回错误代码invalid_grant 。
{
"error": "invalid_grant",
"error_description": "An optional description message that varies between vendors"
}
At this point you should do two things:此时你应该做两件事:
SAMPLE CODE OF MINE我的示例代码
A something to compare against, I have an AppAuth code sample that you can run and which allows simulation of token expiry events:作为对比,我有一个 AppAuth 代码示例,您可以运行它并允许模拟令牌过期事件:
Of course you would need to translate this behaviour to your own Dagger based coding preferences...当然,您需要将此行为转换为您自己的基于 Dagger 的编码首选项......
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.