首页 > 解决方案 > 安卓| 使用改造 2 和本地 API 的基本身份验证

问题描述

我开始制作一个应用程序并将其连接到模拟 API。现在我想将它连接到一个在我的 PC 上运行的 API。

对于初学者,我正在尝试实现登录访问。由于我的 API 的基本 URL 是http://localhost:5000/energy/api/我将其更改为 http://<< MyIPAddress >>:5000/energy/api/ (不知道这是否正确)。我正在我的实际手机上测试它。但是使用我的代码,用户名和密码作为参数传递,而我想使用基本身份验证登录(这就是我在 Postman 中的操作方式)。例如,这就是我希望完成身份验证的方式: 在此处输入图像描述

但是通过我的代码,我得到了这个: 在此处输入图像描述

这是我的请求管理器:

object RequestManager {
    val interceptor = HttpLoggingInterceptor()
    val client = OkHttpClient.Builder().addInterceptor(interceptor).build()
    init {
        interceptor.level = HttpLoggingInterceptor.Level.BODY
    }

    val retrofit = Retrofit.Builder()
        .baseUrl("http://<<MYIP>>:5000/energy/api/")
        .addConverterFactory(GsonConverterFactory.create())
        .client(client)
        .build()

    val service = retrofit.create(Api::class.java)

我的 MainActivity.kt:

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        login_button.setOnClickListener {
            buttonClicked()
        }

        if (getTokenFromPrefs()?.length!! > 0) {
            openSearchActivity()
        }
    }

    private fun buttonClicked() {
        val username = username_edittext.text.toString()
        val password = password_edittext.text.toString()
        Log.d("eeee","button clicked " + username_edittext.text.toString() + " password "+password_edittext.text.toString() )

        val call = RequestManager.service.login(username, password)
        call.enqueue(object : Callback<LoginResponse> {
            override fun onResponse(call: Call<LoginResponse>, response: Response<LoginResponse>) {
                if (response.isSuccessful ){
                        openSearchActivity()
                        saveTokenToPrefs(response.toString())
                    }else {

                }
            }

            override fun onFailure(call: Call<LoginResponse>, t: Throwable) {
            }
        })
    }

    val TOKENPREFSKEY = "tokenprefskey"
    private fun saveTokenToPrefs(token: String) {
        val pref = applicationContext.getSharedPreferences("CGEEnergy", 0)
        val editor = pref.edit()
        editor.putString(TOKENPREFSKEY, token)
        editor.commit()
    }

    private fun getTokenFromPrefs(): String? {
        val pref = applicationContext.getSharedPreferences("CGEEnergy", 0)
        return pref.getString(TOKENPREFSKEY, "")
    }

    private fun openSearchActivity() {
        val intent = Intent(this, SearchActivity::class.java)
        startActivity(intent)
        if (getTokenFromPrefs()?.length!! == 0) {
            openMainActivity()
        }
        finish()
    }
    private fun openMainActivity() {
        val intent = Intent(this, MainActivity::class.java)
        startActivity(intent)
        finish()
    }
}

我的 API.kt 代码:(由用户Hello World编辑和更正)

interface Api {
    @POST("Login")
    @FormUrlEncoded
    fun login(@Field("username") username: String, @Field("password") password: String): Call<LoginResponse>
}

我的 LoginResponse.java 代码:

public class LoginResponse {

    @SerializedName("token")
    @Expose
    private String token;

    public String getToken() {
        return token;
    }

    public void setToken(String token) {
        this.token = token;
    }

}

有人可以帮助我进行基本身份验证吗?我的基本 URL 是否也有问题?(添加 IP 而不是 localhost)。任何提示将不胜感激。

PS。对于http安全问题,我已经添加了

android:usesCleartextTraffic="true"

在我的AndroidManifest.xml

标签: androidapikotlinretrofit2basic-authentication

解决方案


Basic Auth 需要以下格式的 Authorization 标头: "Basic " + Base64.encode(<username>:<password>)

您应该像这样更改您的 Api 界面

interface Api {
    @POST("Login")
    fun login(@Header("Authorization") authorization: String): Call<LoginResponse>
}

现在您可以像这样向调用中添加 Auth 标头:

val authPayload = "$userId:$password"
val data = authPayload.toByteArray()
val base64 = Base64.encodeToString(data, Base64.NO_WRAP)

val call = RequestManager.service.login("Basic $base64".trim())

推荐阅读