我正在使用$(e.target)
与Retrofit 2.0
转换器与Rest API进行通信。某些请求需要令牌才能获得授权。如果我拥有的令牌已过期,我需要用另一个请求刷新它们,并重复上次因此而失败的请求。
我的问题:我是否每次都需要手动执行此操作,还是有任何方法可以自动执行此操作?
这是我目前实施它的方式:
TrackerService
Jackson
ServiceGateway
public interface TrackerService {
@POST("auth/sendPassword")
Call<ResponseMessage> sendPassword(@Header("app-type") String appType,
@Body User userMobile);
@FormUrlEncoded
@POST("oauth/token")
Call<TokenResponse> oathToken(@Field("client_id") String clientId,
@Field("client_secret") String clientSecret,
@Field("grant_type") String grantType,
@Field("username") String username,
@Field("password") String password);
@FormUrlEncoded
@POST("oauth/token")
Call<TokenResponse> refreshToken(@Field("client_id") String clientId,
@Field("client_secret") String clientSecret,
@Field("grant_type") String grantType,
@Field("refresh_token") String username);
@PUT("me/profile")
Call<Profile> updateProfile(@Header("app-type") String appType,
@Header("Authorization") String token,
@Body Profile profile);
}
我如何调用函数并在令牌过期时对其进行处理
public class ServiceGateway {
private static OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
private static Retrofit retrofit;
public static <S> S createService(Class<S> serviceClass) {
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient client = new OkHttpClient.Builder()
.connectTimeout(20 * 1000, TimeUnit.MILLISECONDS)
.writeTimeout(20 * 1000, TimeUnit.MILLISECONDS)
.readTimeout(20 * 1000, TimeUnit.MILLISECONDS)
.addInterceptor(interceptor).build();
Retrofit.Builder builder =
new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(JacksonConverterFactory.create());
retrofit = builder.client(httpClient.build())
.client(client)
.build();
return retrofit.create(serviceClass);
}
public static Retrofit getRetrofit() {
return retrofit;
}
}
答案 0 :(得分:31)
我在2-3个月前搜索了这个主题并找到了OkHttp 's Authenticator
。你可以使用它。这里有一个链接:refreshing-oauth-token-using-retrofit-without-modifying-all-calls
它的工作方式如下:如果您的请求返回401
,则Authenticator
会移入,并刷新您的令牌。但请不要忘记return null
或尝试任何限制。如果您没有限制,它会在刷新请求失败时尝试刷新多次,并在刷新令牌时发出同步请求。
我也有一个问题和答案 - 我自己通过搜索theese链接写的 - 关于刷新Oauth2令牌,也许你会看看它:
问题:android-retrofit2-refresh-oauth-2-token
答案:android-retrofit2-refresh-oauth-2-token-answer
此外:例如,如果您有令牌,则需要每3小时刷新一次。你也可以写一个Interceptor
。在Interceptor
中:比较时间并刷新令牌而不会收到任何401
响应。
您可以阅读Interceptor
页面:OkHttp Interceptors
你也可以看一看:OkHttp handling-authentication
我知道此处没有代码,但请尝试链接并编辑您的问题,然后我会帮助您。
答案 1 :(得分:0)
服务器返回401未经授权时,将调用authenticate()方法。
用于调用ApiFactory.retrofit(“ url”)。create(PostDataInterface :: class.java) .refreshToken(refreshTokenRequest)),我们正在使用execute()使其成为同步调用。
如果刷新令牌状态为0。添加您的功能以注销用户。
interface PostDataInterface {
@POST("refreshUserToken")
fun refreshToken(@Body refreshTokenRequest: RefreshTokenRequest?): Call<RefreshTokenResponse?>?
}
class TokenAuthenticator : Authenticator {
override fun authenticate(route: Route?, response: Response): Request? {
// This is a synchronous call
val updatedToken = getNewToken()
return updatedToken?.let {
response.request.newBuilder().header("Authorization", it)
.build()
}
}
private fun getNewToken(): String? {
val refreshTokenRequest = RefreshTokenRequest(SharedPreferenceHelper.refreshToken)
val call = ApiFactory.retrofit(BuildConfig.BASEURL).create(PostDataInterface::class.java)
.refreshToken(refreshTokenRequest)
val authTokenResponse = call?.execute()?.body()
if (authTokenResponse?.status == 0){
//Logout User
AuthUtility.logout(true)
}
return authTokenResponse?.data?.token
}
}
在Okhttp客户端中添加身份验证器
private val client =
OkHttpClient().newBuilder()
.authenticator(TokenAuthenticator())
...
.build()
答案 2 :(得分:0)
这是刷新令牌验证器的实现
class TokenAuthenticator(
val sharedPrefsHelper: SharedPrefsHelper,
private val identityService: IdentityService
) : Authenticator {
override fun authenticate(route: Route?, response: Response): Request? {
Log.d("TokenAuth Request:", "${response.body}")
val refreshToken = sharedPrefsHelper[SharedPrefsHelper.PREF_KEY_AUTH_REFRESH_TOKEN, null]
if (refreshToken.isNullOrEmpty().not()) {
val requestFields = mutableMapOf<String, String>()
requestFields["refresh_token"] = refreshToken!!
requestFields["grant_type"] = "refresh_token"
try {
val tokenResponse = runBlocking {
identityService.getAuthToken(requestFields)
}
Log.d("TokenAuth Success:", "$tokenResponse")
tokenResponse.accessToken.let { accessToken ->
sharedPrefsHelper.put(
SharedPrefsHelper.PREF_KEY_AUTH_TOKEN,
accessToken
)
sharedPrefsHelper.put(
SharedPrefsHelper.PREF_KEY_AUTH_REFRESH_TOKEN,
tokenResponse.refreshToken
)
return response.request.newBuilder()
.header("Authorization", "Bearer $accessToken")
.build()
}
} catch (e: Exception) {
Log.d("TokenAuth Error:", "$e")
}
}
return null
}
}
<块引用>
使用构建器进行配置 -
return OkHttpClient.Builder()
.authenticator(TokenAuthenticator(sharedPrefsHelper, identityBaseUrl))
.addInterceptor(httpLoggingInterceptor)
.addInterceptor(requestInterceptor).addInterceptor(logging)
.connectTimeout(30, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS)
.writeTimeout(30, TimeUnit.SECONDS)
.build()
还有@Yasin 建议的 -
不要忘记返回 null 或设置任何尝试限制。如果你不限制,它会在你的刷新请求失败时尝试多次刷新。另外,在刷新令牌时发出同步请求。