Retrofit2 Authorization - 访问令牌的全局拦截器
Posted
技术标签:
【中文标题】Retrofit2 Authorization - 访问令牌的全局拦截器【英文标题】:Retrofit2 Authorization - Global Interceptor for access token 【发布时间】:2017-04-26 00:30:24 【问题描述】:我正在尝试使用Retrofit2
,
我想将Token
添加到我的Header
像这样:
Authorization: Bearer Token
但下面的code
不起作用:
public interface APIService
@Headers("Authorization", "Bearer "+ token)
@GET("api/Profiles/GetProfile?id=id")
Call<UserProfile> getUser(@Path("id") String id);
我的服务器是asp.net webApi
。请帮忙,我该怎么办?
【问题讨论】:
这种添加标头的方法仅在 'token' 是编译时间常数时有效。 Java的注解规则等等。文档为您提供了另一种包含标题的方法:square.github.io/retrofit(使其成为方法参数) 【参考方案1】:你有两个选择——你可以将它作为参数添加到你的调用中——
@GET("api/Profiles/GetProfile?id=id")
Call<UserProfile> getUser(@Path("id") String id, @Header("Authorization") String authHeader);
这可能有点烦人,因为您必须在每次调用时传递"Bearer" + token
。如果您没有太多需要令牌的调用,这很适合。
如果你想给所有请求添加header,可以使用okhttp拦截器——
OkHttpClient client = new OkHttpClient.Builder().addInterceptor(new Interceptor()
@Override
public Response intercept(Chain chain) throws IOException
Request newRequest = chain.request().newBuilder()
.addHeader("Authorization", "Bearer " + token)
.build();
return chain.proceed(newRequest);
).build();
Retrofit retrofit = new Retrofit.Builder()
.client(client)
.baseUrl(/** your url **/)
.addConverterFactory(GsonConverterFactory.create())
.build();
【讨论】:
对我来说,直到我实现它时我才意识到,但令牌仅在运行时才知道 - 因此我认为这是一个更好的解决方案:***.com/questions/43051558/… 感谢它为不记名令牌工作,但如何添加带有动态标题的 FieldMap。我尝试过使用 FieldMap,但它不起作用。请帮忙。 第一个案例:“Bearer”+令牌。 “承载者”+令牌。需要空间 第二个问题。方法是如果您使用依赖注入器库。您必须先登录用户,然后在为您的调用实例化 Okhttp 之前获取令牌 最好的方法是使用新的 Authenticator API,***.com/a/31624433/5093308【参考方案2】:如果您想将 Bearer Token 添加为 Header,您可以执行这些类型的过程。
这是使用 Bearer Token
的一种方式在您的界面中
@Headers( "Content-Type: application/json;charset=UTF-8")
@GET("api/Profiles/GetProfile")
Call<UserProfile> getUser(@Query("id") String id, @Header("Authorization") String auth);
之后你会以这种方式调用 Retrofit 对象
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("your Base URL")
.addConverterFactory(GsonConverterFactory.create())
.build();
APIService client = retrofit.create(APIService.class);
Call<UserProfile> calltargetResponse = client.getUser("0034", "Bearer "+token);
calltargetResponse.enqueue(new Callback<UserProfile>()
@Override
public void onResponse(Call<UserProfile> call, retrofit2.Response<UserProfile> response)
UserProfile UserResponse = response.body();
Toast.makeText(this, " "+response.body(), Toast.LENGTH_SHORT).show();
@Override
public void onFailure(Call<UserProfile> call, Throwable t)
//Toast.makeText(this, "Failed ", Toast.LENGTH_SHORT).show();
);
另一种方式是使用拦截,与上一个答案类似。但是,那个时候你只需要修改一下界面就好了。
@Headers( "Content-Type: application/json;charset=UTF-8")
@GET("api/Profiles/GetProfile")
Call<UserProfile> getUser(@Query("id") String id);
希望这对你有用。
【讨论】:
【参考方案3】:基于@iagreen 解决方案 kotlin 版本,具有 @Daniel Wilson 建议的不同类和结构
像这样制作改造实例
object RetrofitClientInstance
private var retrofit: Retrofit? = null
private val BASE_URL = "http://yoururl"
val retrofitInstance: Retrofit?
get()
if (retrofit == null)
var client = OkHttpClient.Builder()
.addInterceptor(ServiceInterceptor())
//.readTimeout(45,TimeUnit.SECONDS)
//.writeTimeout(45,TimeUnit.SECONDS)
.build()
retrofit = Retrofit.Builder()
.baseUrl(BASE_URL)
.client(client)
.addConverterFactory(GsonConverterFactory.create())
.build()
return retrofit
添加ServiceInterceptor
类,如下所示
class ServiceInterceptor : Interceptor
var token : String = "";
fun Token(token: String )
this.token = token;
override fun intercept(chain: Interceptor.Chain): Response
var request = chain.request()
if(request.header("No-Authentication")==null)
//val token = getTokenFromSharedPreference();
//or use Token Function
if(!token.isNullOrEmpty())
val finalToken = "Bearer "+token
request = request.newBuilder()
.addHeader("Authorization",finalToken)
.build()
return chain.proceed(request)
登录接口和数据类实现
interface Login
@POST("Login")
@Headers("No-Authentication: true")
fun login(@Body value: LoginModel): Call<LoginResponseModel>
@POST("refreshToken")
fun refreshToken(refreshToken: String):
Call<APIResponse<LoginResponseModel>>
data class LoginModel(val Email:String,val Password:String)
data class LoginResponseModel (val token:String,val
refreshToken:String)
在这样的任何活动中调用它
val service = RetrofitClientInstance.retrofitInstance?.create(Login::class.java)
val refreshToken = "yourRefreshToken"
val call = service?.refreshToken(refreshToken)
call?.enqueue(object: Callback<LoginResponseModel>
override fun onFailure(call: Call<LoginResponseModel>, t: Throwable)
print("throw Message"+t.message)
Toast.makeText(applicationContext,"Error reading JSON",Toast.LENGTH_LONG).show()
override fun onResponse(call: Call<LoginResponseModel>, response: Response<LoginResponseModel>)
val body = response?.body()
if(body!=null)
//do your work
)
详情this视频会有所帮助。
【讨论】:
【参考方案4】:这会将您的令牌添加到构建器中,您可以在登录/注销时随时更改它。
object ApiService
var YOUR_TOKEN = ""
private var retrofit: Retrofit = Retrofit.Builder()
.baseUrl("YOUR_URL")
.addConverterFactory(GsonConverterFactory.create())
.client(OkHttpClient.Builder().addInterceptor chain ->
val request = chain.request().newBuilder().addHeader("Authorization", "Bearer $YOUR_TOKEN").build()
chain.proceed(request)
.build())
.build()
var service: AppAPI = retrofit.create(AppAPI::class.java)
private set
【讨论】:
这是否意味着每次令牌更改时我都必须调用 Retrofit.Builder() ?我以为我构建了一次改造,然后登录,登录后我使用令牌直到它过期。我还不明白。 :)【参考方案5】:您需要将拦截器添加到OkHttpClient
。
添加一个名为OAuthInterceptor
的类。
class OAuthInterceptor(private val tokenType: String, private val accessToken: String) : Interceptor
override fun intercept(chain: Interceptor.Chain): okhttp3.Response
var request = chain.request()
request = request.newBuilder().header("Authorization", "$tokenType $accessToken").build()
return chain.proceed(request)
接下来,当您初始化RetrofitApiService
接口时,您将需要这个。
interface RetrofitApiService
companion object
private const val BASE_URL = "https://api.coursera.org/api/businesses.v1/"
fun create(accessToken: String): RetrofitApiService
val client = OkHttpClient.Builder()
.addInterceptor(OAuthInterceptor("Bearer", accessToken))
.build()
val retrofit = Retrofit.Builder()
.addConverterFactory(GsonConverterFactory.create())
.baseUrl(BASE_URL)
.client(client)
.build()
return retrofit.create(RetrofitApiService::class.java)
向 Java Code Monk 致敬,并访问参考链接了解更多详细信息。 https://www.javacodemonk.com/retrofit-oauth2-authentication-okhttp-android-3b702350
【讨论】:
【参考方案6】:最好的方法是使用新的 Authenticator API。
class TokenAuthenticator : Authenticator
override fun authenticate(route: Route?, response: Response): Request?
if (response.request.header("Authorization") != null)
return null
return response.request.newBuilder().header("Authorization", "Bearer " + token).build()
OkHttpClient.Builder().authenticator(TokenAuthenticator()).build()
参考:https://square.github.io/okhttp/recipes/#handling-authentication-kt-java
【讨论】:
以上是关于Retrofit2 Authorization - 访问令牌的全局拦截器的主要内容,如果未能解决你的问题,请参考以下文章