Retrofit2 Authorization - Global Interceptor für Zugriffstoken

76

Ich versuche zu verwenden Retrofit2, ich möchte Tokenmein HeaderGefällt mir hinzufügen :

Authorization: Bearer Token aber das codefolgende funktioniert nicht:

public interface APIService {
    @Headers({"Authorization", "Bearer "+ token})
    @GET("api/Profiles/GetProfile?id={id}")
    Call<UserProfile> getUser(@Path("id") String id);
}

Mein Server ist asp.net webApi. Bitte helfen Sie, was soll ich tun?

Farshad
quelle
Diese Art des Hinzufügens eines Headers funktioniert nur, wenn 'Token' eine Kompilierungszeitkonstante ist. Javas Anmerkungsregeln und so weiter. Die Dokumentation bietet Ihnen eine andere Möglichkeit, einen Header einzuschließen : square.github.io/retrofit (machen Sie ihn zu einem Methodenparameter)
zapl

Antworten:

133

Sie haben zwei Möglichkeiten - Sie können es als Parameter zu Ihrem Anruf hinzufügen -

@GET("api/Profiles/GetProfile?id={id}")
Call<UserProfile> getUser(@Path("id") String id, @Header("Authorization") String authHeader);

Dies kann etwas ärgerlich sein, da Sie "Bearer" + tokenbei jedem Anruf das übergeben müssen. Dies ist geeignet, wenn Sie nicht sehr viele Anrufe haben, für die das Token erforderlich ist.

Wenn Sie den Header zu allen Anforderungen hinzufügen möchten, können Sie einen okhttp-Interceptor verwenden -

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();
iagreen
quelle
1
Für mich war es nicht klar, bis ich es implementiert hatte, aber das Token ist nur zur Laufzeit bekannt - daher denke ich, dass dies eine bessere Lösung ist: stackoverflow.com/questions/43051558/…
Daniel Wilson
Vielen Dank, dass es für Inhaber-Token funktioniert, aber wie man FieldMap mit Dyanamik-Header hinzufügt. Ich habe es mit FieldMap versucht, aber es funktioniert nicht. Bitte helfen Sie.
Dildarkhan Pathan
erster Fall: "Träger" + Token. "Träger" + Token. Brauchen Sie leeren Raum
Cristianego
22

Wenn Sie Bearer Token als Header hinzufügen möchten, können Sie diese Arten von Prozessen ausführen.

Dies ist eine Möglichkeit, mit Bearer Token zu arbeiten

In Ihrer Schnittstelle

@Headers({ "Content-Type: application/json;charset=UTF-8"})
@GET("api/Profiles/GetProfile")
Call<UserProfile> getUser(@Query("id") String id, @Header("Authorization") String auth);

Danach rufen Sie das Retrofit-Objekt auf diese Weise auf

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();
        }
});

Ein anderer Weg ist die Verwendung von Intercept, ähnlich wie in der vorherigen Antwort. Aber dieses Mal müssen Sie nur die Oberfläche ein wenig wie ändern.

@Headers({ "Content-Type: application/json;charset=UTF-8"})
@GET("api/Profiles/GetProfile")
Call<UserProfile> getUser(@Query("id") String id); 

Hoffe das wird für dich funktionieren.

Hamza Rahman
quelle
9

Basierend auf der Kotlin-Version der @iagreen-Lösung mit verschiedenen Klassen und Strukturen, die von @Daniel Wilson vorgeschlagen wurde

Machen Sie die Retrofit-Instanz so

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
      }

}

ServiceInterceptorKlasse wie unten hinzufügen

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)
  }

}

Anmeldeschnittstelle und Implementierung der Datenklasse

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)

Nennen Sie dies in einer solchen Aktivität

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
                }
            }

        })

Für Details wird dieses Video hilfreich sein.

Faraz Ahmed
quelle
4

Dadurch wird Ihr Token dem Builder hinzugefügt und Sie können es jederzeit ändern, wenn Sie sich anmelden oder abmelden.

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

}
cibernato
quelle
Bedeutet das, dass ich Retrofit.Builder () jedes Mal aufrufen muss, wenn sich das Token ändert? Ich dachte, ich erstelle Retrofit einmal, dann logge ich mich ein und nach dem Login benutze ich das Token, bis es abläuft. Ich verstehe es noch nicht. :)
Der unglaubliche
1

Sie müssen einen Interceptor zum hinzufügen OkHttpClient.

Fügen Sie eine Klasse mit dem Namen hinzu 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)
    }
}

Wenn Sie anschließend Ihre RetrofitApiServiceSchnittstelle initialisieren , benötigen Sie diese.

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)
        }
    }
}

Rufen Sie Java Code Monk an und besuchen Sie den Referenzlink für weitere Details. https://www.javacodemonk.com/retrofit-oauth2-authentication-okhttp-android-3b702350

Morgan Koh
quelle