Android App 用户登录与会话管理

Author: System
Date: May 5, 2025

实现用户登录

用户登录是Android应用的核心功能,通常涉及身份验证、数据存储和网络请求。以下是实现用户登录的主要步骤和最佳实践。

1. 设计登录界面

使用XML布局文件设计用户界面,包含用户名、密码输入框和登录按钮。确保界面简洁,支持输入验证。

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="16dp">
    <EditText
        android:id="@+id/username"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="用户名"/>
    <EditText
        android:id="@+id/password"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="密码"
        android:inputType="textPassword"/>
    <Button
        android:id="@+id/loginButton"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="登录"/>
</LinearLayout>
    

2. 处理用户输入

在Activity或Fragment中获取用户输入,验证格式(如非空、邮箱格式)。使用View Binding或Kotlin合成属性简化代码。

// Kotlin 示例
loginButton.setOnClickListener {
    val username = usernameEditText.text.toString()
    val password = passwordEditText.text.toString()
    if (username.isNotEmpty() && password.isNotEmpty()) {
        performLogin(username, password)
    } else {
        Toast.makeText(this, "请输入用户名和密码", Toast.LENGTH_SHORT).show()
    }
}
    

3. 与后端通信

使用Retrofit或OkHttp发送HTTP请求到后端API进行身份验证。推荐使用JSON格式的POST请求,包含用户名和密码。

// Retrofit 接口定义
interface AuthService {
    @POST("login")
    suspend fun login(@Body request: LoginRequest): Response<LoginResponse>
}

data class LoginRequest(val username: String, val password: String)
data class LoginResponse(val token: String, val userId: String)
    

最佳实践:使用HTTPS确保数据安全,添加超时和重试机制处理网络问题。

4. 处理登录响应

从后端接收JWT(JSON Web Token)或其他认证令牌,验证响应状态并存储令牌。

// 处理登录响应
viewModelScope.launch {
    try {
        val response = authService.login(LoginRequest(username, password))
        if (response.isSuccessful) {
            val token = response.body()?.token
            saveToken(token) // 存储令牌
            navigateToMainScreen()
        } else {
            showError("登录失败")
        }
    } catch (e: Exception) {
        showError("网络错误")
    }
}
    

保持用户会话

保持用户会话需要安全存储认证令牌并在后续请求中携带。以下是实现方法和最佳实践。

1. 存储认证令牌

使用 SharedPreferencesEncryptedSharedPreferences 存储令牌。推荐使用加密存储保护敏感数据。

// 使用 EncryptedSharedPreferences
val masterKey = MasterKey.Builder(context)
    .setKeyScheme(MasterKey.KeyScheme.AES256_GCM)
    .build()

val sharedPreferences = EncryptedSharedPreferences.create(
    context,
    "auth_prefs",
    masterKey,
    EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
    EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
)

fun saveToken(token: String?) {
    sharedPreferences.edit().putString("auth_token", token).apply()
}
    

2. 自动登录

在应用启动时检查存储的令牌是否有效。若有效,直接进入主界面;若无效,跳转到登录页面。

// 检查令牌
fun checkSession(): Boolean {
    val token = sharedPreferences.getString("auth_token", null)
    return if (token != null) {
        verifyToken(token) // 可选:验证令牌有效性
        true
    } else {
        false
    }
}
    

3. 在请求中携带令牌

在每个API请求的头部添加认证令牌(如 Authorization: Bearer <token>)。

// Retrofit 拦截器
val authInterceptor = Interceptor { chain ->
    val token = sharedPreferences.getString("auth_token", null)
    val newRequest = chain.request().newBuilder()
        .addHeader("Authorization", "Bearer $token")
        .build()
    chain.proceed(newRequest)
}

val okHttpClient = OkHttpClient.Builder()
    .addInterceptor(authInterceptor)
    .build()
    

4. 令牌刷新机制

为避免令牌过期,设置刷新令牌机制。使用后端提供的刷新API定期更新令牌。

// 刷新令牌
interface AuthService {
    @POST("refresh")
    suspend fun refreshToken(@Body request: RefreshRequest): Response<LoginResponse>
}

data class RefreshRequest(val refreshToken: String)

// 拦截器检测401错误并刷新
val authInterceptor = Interceptor { chain ->
    val response = chain.proceed(chain.request())
    if (response.code == 401) {
        val newToken = refreshTokenSynchronously()
        val newRequest = chain.request().newBuilder()
            .header("Authorization", "Bearer $newToken")
            .build()
        chain.proceed(newRequest)
    } else {
        response
    }
}
    

最佳实践

  • 安全性:始终使用HTTPS,加密存储令牌,避免明文传输敏感数据。
  • 用户体验:提供加载动画和错误提示,优化登录流程。
  • 性能:使用协程或RxJava处理异步任务,避免阻塞UI线程。
  • 可维护性:采用MVVM架构,将登录逻辑与UI分离,使用依赖注入(如Hilt)管理依赖。
  • 令牌管理:实现令牌过期检测和自动刷新,减少用户重新登录的频率。

AD