上一篇
安卓多后台单点登录问题cas
- 行业动态
- 2025-04-21
- 4
问题背景分析
在安卓应用开发中,”多后台单点登录”通常指应用在多个后台进程/服务中共享同一登录状态,结合CAS(Central Authentication Service)实现时,需解决以下核心问题:
- 跨进程状态共享:安卓不同进程间数据不共享,需设计统一认证状态存储方案。
- 票据(Ticket)管理:CAS的ST/LT票据需安全存储、自动刷新并同步到所有后台进程。
- 后台服务认证:后台服务需自动获取有效票据,避免重复登录或认证失效。
关键技术方案
跨进程认证状态共享
方案 | 实现方式 | 优缺点 |
---|---|---|
AccountManager | 利用系统账户管理器存储全局凭证 | 系统级支持,适合敏感数据;需适配不同安卓版本权限 |
文件存储+广播通知 | 将票据写入文件,通过广播通知其他进程更新 | 简单易用;需处理文件读写冲突 |
ContentProvider | 通过自定义Provider实现跨进程数据访问 | 灵活性高;需处理多线程并发 |
SharedPreferences(多进程模式) | 使用MODE_MULTI_PROCESS 模式 | 快速实现;数据一致性依赖调用时机 |
票据自动刷新与同步
- 票据存储:将CAS返回的票据(如
ST-xxx
)加密后存入共享存储(推荐使用AccountManager
)。 - 刷新机制:
- 主进程监听票据过期时间(可通过HTTP头或CAS接口获取)。
- 到期前触发静默刷新(携带旧票据请求新票据)。
- 广播
ACTION_TICKET_REFRESHED
通知其他进程更新。
- 后台服务处理:
// 示例:后台服务接收票据更新广播 BroadcastReceiver ticketReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { String newTicket = intent.getStringExtra("ticket"); // 更新本地存储的票据 AccountManager.get(context).setAuthToken(ACCOUNT_TYPE, newTicket); } };
后台服务集成CAS认证
- 服务启动时获取票据:
// 从AccountManager获取当前票据 AccountManager accountManager = AccountManager.get(context); String ticket = accountManager.peekAuthToken(account, ACCOUNT_TYPE); if (ticket != null) { // 携带票据调用API callApiWithTicket(ticket); } else { // 触发登录流程 triggerLogin(); }
- 错误处理:若API返回401,需触发票据刷新流程。
完整实现流程
- 初始化阶段:
- 检查
AccountManager
中是否存在有效账户和票据。 - 若无则跳转登录页面,引导用户完成CAS认证。
- 检查
- 登录流程:
- 用户输入CAS账号密码,前端发起CAS登录请求。
- 登录成功后,将票据存入
AccountManager
,并广播ACTION_LOGIN_SUCCESS
。
- 后台服务启动:
- 注册
ticketReceiver
监听票据更新广播。 - 从
AccountManager
获取票据并发起带票请求。
- 注册
- 票据刷新:
- 主进程检测票据剩余有效期(如<30秒)。
- 静默调用CAS刷新接口,更新票据并广播通知。
常见问题与解答
问题1:如何保证多进程下票据存储的一致性?
解答:推荐使用AccountManager
,因其设计为系统级跨进程账户存储,若需更高灵活性,可结合ContentProvider
实现自定义存储,并在每次写入后发送广播通知其他进程同步数据。
问题2:后台服务如何避免因票据过期导致认证失败?
解答:
- 主动刷新:在主进程中监控票据有效期,提前刷新。
- 容错重试:后台服务捕获401错误后,触发票据刷新逻辑并重试请求。
- 缓存机制:短期缓存API响应数据,减少重复认证请求。
代码示例(关键片段)
// 存储票据到AccountManager AccountManager accountManager = AccountManager.get(context); Account account = new Account(username, ACCOUNT_TYPE); accountManager.setAuthToken(account, "full_access", ticket); // 广播票据更新 Intent intent = new Intent("ACTION_TICKET_REFRESHED"); intent.putExtra("ticket", newTicket); LocalBroadcastManager.getInstance(context).sendBroadcast(intent); // 后台服务获取票据 String ticket = accountManager.peekAuthToken(account, "full_access"); if (ticket != null) { // 调用带票API } else { // 触发登录流程 }
相关工具与库
工具/库 | 用途 | 说明 |
---|---|---|
Android AccountManager | 跨进程认证存储 | 系统级支持,适合敏感数据 |
OkHttp + Interceptor | 自动携带票据 | 通过拦截器注入票据到请求头 |
WorkManager | 定时刷新票据 | 替代AlarmManager,兼容不同安卓版本 |