简体   繁体   中英

http 401 unauthorized retrofit kotlin

I'm trying to pull data by connecting to a web service using Retrofit. I can extract data from an unencrypted web service with the codes I use. The web service I will use in my application is encrypted. so i get this error: "http 401 unauthorized". In Postman I can access the data by entering name and password. I also use bearer token. I couldn't find the code despite searching a lot. Can you help?

example web service auth name: "exampleusername", password: " examplepassword "

object RetrofitBuilder {

     private const val BASE_URL = "https://www.examplewebservice.com/Api/"

    private fun getRetrofit(): Retrofit {
        return Retrofit.Builder()
            .baseUrl(BASE_URL)
            .addConverterFactory(GsonConverterFactory.create())
            .build()
    }

    val apiService: ApiService = getRetrofit().create(ApiService::class.java)

}
interface ApiService {

  @GET("users")
  suspend fun getUsers(): List<User>

}
class ApiHelper(private val apiService: ApiService) {

    suspend fun getUsers() = apiService.getUsers()
}
data class User(

    val id: String,
    val name: String
)
class MainRepository(private val apiHelper: ApiHelper) {

    suspend fun getUsers() = apiHelper.getUsers()
}
class ViewModelFactory(private val apiHelper: ApiHelper) : ViewModelProvider.Factory {

    override fun <T : ViewModel> create(modelClass: Class<T>): T {
        if (modelClass.isAssignableFrom(MainViewModel::class.java)) {
            return MainViewModel(MainRepository(apiHelper)) as T
        }
        throw IllegalArgumentException("Unknown class name")
    }


}
class MainViewModel(private val mainRepository: MainRepository) : ViewModel() {

    fun getUsers() = liveData(Dispatchers.IO) {
        emit(Resource.loading(data = null))
        try {
            emit(Resource.success(data = mainRepository.getUsers()))
        } catch (exception: Exception) {
            emit(Resource.error(data = null, message = exception.message ?: "Error Occurred!"))
        }
    }
}
data class Resource<out T>(val status: Status, val data: T?, val message: String?) {
    companion object {
        fun <T> success(data: T): Resource<T> = Resource(status = SUCCESS, data = data, message = null)

        fun <T> error(data: T?, message: String): Resource<T> =
            Resource(status = ERROR, data = data, message = message)

        fun <T> loading(data: T?): Resource<T> = Resource(status = LOADING, data = data, message = null)
    }
}
class MainActivity : AppCompatActivity() {

    private lateinit var viewModel: MainViewModel
    private lateinit var adapter: MainAdapter



    override fun onCreate(savedInstanceState: Bundle?) {

        super.onCreate(savedInstanceState)
        setContentView(layout.activity_main)
        setupViewModel()
        setupUI()
        setupObservers()
    }


    private fun setupViewModel() {
        viewModel = ViewModelProvider(this,ViewModelFactory(ApiHelper(RetrofitBuilder.apiService))).get(MainViewModel::class.java)
    }

    private fun setupUI() {
        recyclerView.layoutManager = LinearLayoutManager(this)
        adapter = MainAdapter(arrayListOf())
        recyclerView.addItemDecoration(
            DividerItemDecoration(
                recyclerView.context,
                (recyclerView.layoutManager as LinearLayoutManager).orientation
            )
        )
        recyclerView.adapter = adapter
    }

    private fun setupObservers() {
        viewModel.getUsers().observe(this, Observer {
            it?.let { resource ->
                when (resource.status) {
                    SUCCESS -> {
                        recyclerView.visibility = View.VISIBLE
                        progressBar.visibility = View.GONE
                        resource.data?.let { users -> retrieveList(users) }
                    }
                    ERROR -> {
                        recyclerView.visibility = View.VISIBLE
                        progressBar.visibility = View.GONE
                        Toast.makeText(this, it.message, Toast.LENGTH_LONG).show()
                    }
                    LOADING -> {
                        progressBar.visibility = View.VISIBLE
                        recyclerView.visibility = View.GONE
                    }
                }
            }
        })
    }

    private fun retrieveList(users: List<User>) {
        adapter.apply {
            addUsers(users)
            notifyDataSetChanged()
        }
    }

    implementation 'com.squareup.retrofit2:retrofit:2.6.0'
    implementation 'com.google.code.gson:gson:2.8.5'
    implementation 'com.squareup.retrofit2:converter-gson:2.5.0'
    implementation 'com.squareup.okhttp3:logging-interceptor:3.12.0'

    implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.9'

    // - -- -- all LifeCycle   - -- - -


    "name": example1,
    "id": 1,
    
  },
  {
    "name": example2,
    "id": 2,
    
  },

private const val BASE_URL="https://www.examplewebservice.com/Api/UserName=examplemurat&Password=examplepassword/"

When I try this I get this error:

"use jsonreader.setlenient(true) to accept malformed json at line 1 column 1 path $"

Based on your comment, I'm assuming the web service you're calling needs a "basic" authentication header in the request.

With that assumption, you can simply add a header to requests made by Retrofit this way:

interface ApiService {
    // for simplicity, the response is just a string
    @GET("users")
    fun getUsers(@Header("Authorization") authorization: String): Call<String>
}

Then, when you want to call that API you have to supply valid credentials:

val credentials = Credentials.basic("myusername", "mypassworda")
val result = apiService.getUsers(credentials).execute()

If you have multiple endpoints you need to call and all need that form of authentication, you can consider adding an interceptor to take care of auth. This means you can keep your current ApiService , and just add an interceptor to the OkHttpClient :

class AuthInterceptor: Interceptor {
    override fun intercept(chain: Interceptor.Chain): Response {
        val requestBuilder = chain.request().newBuilder()
        val credentials = Credentials.basic("myusername", "mypassword")
        requestBuilder.addHeader("Authorization", credentials)
        return chain.proceed(requestBuilder.build())
    }
}

...

val httpClientWithAuth = OkHttpClient.Builder()
    .addInterceptor(AuthInterceptor())
    .build()

val apiService = Retrofit.Builder()
    .baseUrl(...)
    .client(httpClientWithAuth)
    ...

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM