【问题标题】:Retrofit2 Authorization - Global Interceptor for access tokenRetrofit2 Authorization - 访问令牌的全局拦截器
【发布时间】: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(使其成为方法参数)

标签: android retrofit okhttp


【解决方案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();

【讨论】:

  • 对我来说,直到我实现它时我才意识到,但令牌仅在运行时才知道 - 因此我认为这是一个更好的解决方案:stackoverflow.com/questions/43051558/…
  • 感谢它为不记名令牌工作,但如何添加带有动态标题的 FieldMap。我尝试过使用 FieldMap,但它不起作用。请帮忙。
  • 第一个案例:“Bearer”+令牌。 “承载者”+令牌。需要空间
  • 第二个问题。方法是如果您使用依赖注入器库。您必须先登录用户,然后在为您的调用实例化 Okhttp 之前获取令牌
  • 最好的方法是使用新的 Authenticator API,stackoverflow.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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2023-03-23
          • 2017-01-27
          • 2021-12-28
          • 2020-03-04
          • 2019-08-11
          • 1970-01-01
          • 1970-01-01
          • 2016-07-02
          相关资源
          最近更新 更多