我在使用匕首2时遇到问题。简要地说,匕首2在片段中进行注入,并且令牌已过期。 TokenAuthenticator要求保存在SharedPreferences中的新令牌。
不会重新创建我的片段,并且匕首2使用过期的令牌而不是新令牌来进行呼叫。
现在我将详细解释。
我的匕首2逻辑微不足道。
NetworkModule.java
@Provides
@Nullable
String provideAuthToken(Context context) {
return AccountUtils.getCurrentUserToken(context);
}
@Provides
AuthenticationInterceptor provideInterceptor(@Nullable String authToken) {
return new AuthenticationInterceptor(authToken);
}
@Provides
TokenAuthenticator provideAuthenticator(Context context, @Nullable String authToken) {
return new TokenAuthenticator(context, authToken);
}
@Provides
OkHttpClient.Builder provideOkHttpClientBuilder(AuthenticationInterceptor interceptor, TokenAuthenticator authenticator) {
OkHttpClient.Builder okHttpClientBuilder = new OkHttpClient.Builder();
okHttpClientBuilder.connectTimeout(15, TimeUnit.SECONDS);
okHttpClientBuilder.readTimeout(15, TimeUnit.SECONDS);
okHttpClientBuilder.writeTimeout(15, TimeUnit.SECONDS);
if (!okHttpClientBuilder.interceptors().contains(interceptor)) {
okHttpClientBuilder.addInterceptor(interceptor);
okHttpClientBuilder.authenticator(authenticator);
}
return okHttpClientBuilder;
}
它从SharedPreferences
获取令牌,并进行改装以调用API。
然后我对API进行简单调用(这是具有授权令牌的GET)
ProfileFragment.java
@Inject
ViewModelFactory viewModelFactory;
UserViewModel userViewModel;
@Override
public void onAttach(Context context) {
((BaseApplication) context.getApplicationContext())
.getAppComponent()
.inject(this);
super.onAttach(context);
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_profile, container, false);
...
userViewModel = ViewModelProviders.of(this, viewModelFactory).get(UserViewModel.class);
userViewModel.getUserInfoMutableLiveData().observe(this, this::consumeResponse);
...
}
private void consumeResponse(UserResponse userResponse) {
switch (userResponse.status) {
case LOADING:
showProgressBar();
break;
case SUCCESS:
handleSuccessResponse(userResponse.data);
break;
case ERROR:
dismissAll();
if (getActivity() != null) {
ResponseHelper.handleErrorResponse(getActivity(), userResponse.error,
mContainer, mMainContainer, this);
}
break;
}
}
现在让我解释发生了什么。
ProfileFragment已创建,匕首2使用注入方式通过获取保存在SharedPreferences
中的令牌来创建组件。
ProfileFragment对该API进行了调用,由于令牌已过期,它会收到401错误代码。
调用 TokenAuthenticatior刷新令牌,它成功刷新令牌并将 NEW 令牌保存在SharedPreferences
中。
再次调用用户信息,但是,由于没有重新创建ProfileFragment,它使用具有旧令牌的相同依赖项注入进行调用。它使用旧令牌调用API,然后出现错误401。
如果我现在离开此页面然后再返回,它将正常工作,因为它再次进行了依赖项注入并获取了保存在SharedPreferences
中的新令牌。
希望有人会帮助您。谢谢!
答案 0 :(得分:1)
在当前作用域生存期内注入更改的东西通常是一个坏主意,因为您不能再注入某些东西。一旦令牌失效,您就必须重新创建整个组件,在这种情况下,您还必须强制重新创建片段。
更好的方法是让您的TokenAuthenticator
和AuthenticationInterceptor
依赖于AccountUtils
,然后他们可以根据需要读取和更新令牌。无需将401传播给用户,因为您可以在身份验证器中以静默方式刷新令牌。
答案 1 :(得分:1)
正如@David Medenjak在接受的答案中指出的那样。我确实使我的TokenAuthentication
和AuthenticationInterceptor
直接依赖令牌,而不是在NetworkModule
中提供令牌。
NetworkModule.java
@Provides
AuthenticationInterceptor provideInterceptor(Context context) {
return new AuthenticationInterceptor(context);
}
@Provides
TokenAuthenticator provideAuthenticator(Context context) {
return new TokenAuthenticator(context);
}
现在,NetworkModule
不再有对该令牌的引用。
AuthenticationInterceptor
直接引用保存在SharedPreferences
中的令牌。
public AuthenticationInterceptor(Context context) {
this.context = context;
}
@Override
public Response intercept(@NonNull Chain chain) throws IOException {
String authToken = AccountUtils.getCurrentUserToken(context);
Request request = chain.request();
Request.Builder newRequest;
if (authToken != null) {
int index = authToken.lastIndexOf(".");
newRequest = request.newBuilder().header(Constants.AUTHORIZATION, authToken);
} else {
newRequest = request.newBuilder();
}
return chain.proceed(newRequest.build());
}
通过这种方式,即使我们使用的是AuthenticationInterceptor
的相同实例,它也会在每个请求中都要求保存在SharedPreferences
中的令牌。然后,我们将根据需要成功刷新令牌。