You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于CRUD操作、MySQL+PHP API后端的Android应用如何实现用户持久登录(主动登出前保持登录状态)

实现Android应用持久化登录(主动登出前保持登录)的方案

嘿,这个需求算是移动端开发里的常规操作了,结合你用的Android+PHP+MySQL技术栈,我给你整理一套落地性强的实现思路,一步步来:

一、核心逻辑:本地存凭证 + 后端验有效性

本质就是把用户的登录状态凭证安全存在本地,每次APP启动先校验凭证是否有效——有效就直接进主界面;只有用户主动点登出时,才清除本地凭证并通知后端让凭证失效。

二、具体实现步骤

1. 后端PHP生成并绑定持久化登录Token

当用户账号密码验证通过后,后端要生成一个唯一、难伪造的登录Token,可选两种方案:

  • 用JWT(JSON Web Token):自带签名验证,安全性高,还能嵌入用户信息;
  • 生成超长随机串:比如用bin2hex(random_bytes(32))生成64位的随机字符串,简单直接。

把这个Token存在MySQL用户表的新增字段(比如login_token)里,再返回给Android客户端。

示例PHP代码片段:

// 假设账号密码校验已通过,拿到用户ID
$userId = $user['id'];
// 生成随机Token
$loginToken = bin2hex(random_bytes(32));
// 更新用户表的Token字段
$stmt = $pdo->prepare("UPDATE users SET login_token = ? WHERE id = ?");
$stmt->execute([$loginToken, $userId]);
// 返回Token和用户基础信息给客户端
echo json_encode(['code' => 200, 'token' => $loginToken, 'userId' => $userId]);

2. Android端安全存储登录凭证

绝对不能用明文存!推荐用AndroidX提供的EncryptedSharedPreferences,它会对存储的内容加密,就算APP被root,凭证也不容易泄露。

示例Android代码:

初始化加密存储:

// 可以在Application类或者工具类里全局初始化
val masterKeyAlias = MasterKeys.getOrCreate(MasterKeys.AES256_GCM_SPEC)
val securePrefs = EncryptedSharedPreferences.create(
    "login_secure_storage",
    masterKeyAlias,
    applicationContext,
    EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
    EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
)

登录成功后存储凭证:

// 接口返回成功后,把Token和用户ID存进去
val editor = securePrefs.edit()
editor.putString("login_token", response.token)
editor.putInt("user_id", response.userId)
editor.apply()

3. APP启动时自动校验登录状态

每次打开APP,先从加密存储里读Token:

  • 有Token就调用后端的Token校验接口,确认Token和用户表中的记录一致;
  • 校验通过直接跳主界面;
  • 校验失败(比如Token被篡改、后端已标记失效),就清除本地凭证跳登录页。

示例Android闪屏页逻辑:

val loginToken = securePrefs.getString("login_token", null)
if (loginToken != null) {
    // 调用后端校验接口
    apiService.verifyToken(loginToken).enqueue(object : Callback<VerifyResult> {
        override fun onResponse(call: Call<VerifyResult>, response: Response<VerifyResult>) {
            if (response.isSuccessful && response.body()?.isValid == true) {
                // 校验通过,跳主界面
                startActivity(Intent(this@SplashActivity, MainActivity::class.java))
            } else {
                // 校验失败,清凭证跳登录
                securePrefs.edit().clear().apply()
                startActivity(Intent(this@SplashActivity, LoginActivity::class.java))
            }
        }

        override fun onFailure(call: Call<VerifyResult>, t: Throwable) {
            // 网络失败时,可以根据业务选择:要么缓存判断,要么直接跳登录
            startActivity(Intent(this@SplashActivity, LoginActivity::class.java))
        }
    })
} else {
    // 无凭证,直接跳登录
    startActivity(Intent(this@SplashActivity, LoginActivity::class.java))
}

后端校验Token的PHP代码:

$token = $_POST['token'] ?? '';
$stmt = $pdo->prepare("SELECT id FROM users WHERE login_token = ?");
$stmt->execute([$token]);
$user = $stmt->fetch(PDO::FETCH_ASSOC);

if ($user) {
    echo json_encode(['code' => 200, 'isValid' => true]);
} else {
    echo json_encode(['code' => 401, 'isValid' => false]);
}

4. 主动登出的完整逻辑

用户点登出按钮时,必须做两件事:

  1. 调用后端登出接口,把用户表中的login_token设为null,让该Token彻底失效;
  2. 清除本地加密存储里的所有登录凭证,然后跳登录页。

示例Android登出代码:

// 点击登出按钮时触发
apiService.logout(securePrefs.getString("login_token", "")).enqueue(object : Callback<LogoutResult> {
    override fun onResponse(call: Call<LogoutResult>, response: Response<LogoutResult>) {
        // 不管后端是否成功,都清本地凭证(避免后端失败但本地还存着)
        securePrefs.edit().clear().apply()
        startActivity(Intent(this@MainActivity, LoginActivity::class.java))
        finish()
    }

    override fun onFailure(call: Call<LogoutResult>, t: Throwable) {
        // 网络失败也强制清本地,保证状态一致
        securePrefs.edit().clear().apply()
        startActivity(Intent(this@MainActivity, LoginActivity::class.java))
        finish()
    }
})

后端登出接口PHP代码:

$token = $_POST['token'] ?? '';
$stmt = $pdo->prepare("UPDATE users SET login_token = NULL WHERE login_token = ?");
$stmt->execute([$token]);
echo json_encode(['code' => 200, 'msg' => '登出成功']);

三、额外注意事项

  • 安全第一:绝对不要存明文密码,只存Token;EncryptedSharedPreferences一定要用,别图省事用普通SharedPreferences;
  • Token防伪造:如果不用JWT,自定义Token要足够长(至少64位)且随机,避免被猜解;
  • 多设备兼容:如果要支持多设备同时登录,后端可以用关联表存储多个Token,登出时只失效当前Token;
  • 异常处理:比如用户在其他设备登出,当前设备下次请求API会收到Token失效响应,这时候要自动清本地凭证跳登录。

内容的提问来源于stack exchange,提问作者Jahanzeb

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.29 23:32:29