框架设计目标
- 提供更高的灵活性,满足不同业务场景的鉴权需求
- 对现有代码侵入性低,教室客户端各业务模块无需感知鉴权逻辑的存在(拦截器)
- 尽可能降低因为鉴权逻辑导致教室指标的劣化(缓存 + 提前获取)
Cookie、Token 的区别
Cookie 主要指 Session ID 存储到 Cookie 中进行的验证的方式,该方式存在一些弊端:
- 服务端需要存储 Session 信息,扩展性差
- 跨域资源共享成本高,容易出现权限问题
- 教室后台无法获取宿主的 Session 信息
Token 是无状态的,服务端不需要保存用户信息,方便服务端扩展,可以跨域共享
客户端流程
- 宿主端:通过账户名、密码登陆
- 实现 Token 获取接口(需要特殊处理无网、SDK未初始化的情况)
- 登出后主动调用教室的 Token 失效接口
- 登入后主动调用教室的 Token 刷新接口
- 进教室前需要判断本地缓存的 Token 是否有效
- 如果存在有效 Token,则直接调用进教室接口
- 如果不存在有效 Token,则应该先调用 Token 刷新接口,设置超时时间并监听 Token 更新成功后调用进教室接口
- Token 自身携带到期时间,内部通过读取 Token 过期时间来维护自动刷新逻辑
- 通过 Interceptor 处理网络请求
- 拦截器内部自动添加 Header 信息
- 拦截器内部判断 body 中存在 ERR_NO 字段,且具体错误类型为 TOKEN_INVALID,则主动触发 Token 刷新
- 每次强制刷新 Token 都会新启动一个 Task 并结束之前的 Task,在 Task 内部会维护自身状态,并通过 retryWhen 来控制失败重试逻辑
enum class State {
/**
* task初始化状态
*/
INITIALIZED,
/**
* task调度前准备阶段
*/
PREPARING,
/**
* task重试期间等待状态
*/
WAITING,
/**
* task执行状态
*/
LOADING,
/**
* task结束状态
*/
CLOSED
}
主要接口设计
interface AuthorizationManager {
/**
* 刷新 Token
* @param force 是否强制刷新, 如果内部正在刷新,则忽略
*/
fun updateToken(force: Boolean)
/**
* 使 Token 失效
*/
fun invalidToken()
/**
* 获取 Token 信息
*/
fun token(): Token?
/**
* 获取 Token 信息
*/
fun getTokenObservable(): Observable<Token>
}
class AuthorizationConfig {
/**
* 获取 Token 接口,由宿主实现
*/
val tokenProvider: TokenProvider
}
interface TokenRefreshScheduler {
/**
* 定时刷新
*/
fun scheduleRefresh(delay: Long)
/**
* 立即刷新
*/
fun refreshNow()
/**
* 尝试刷新,如果当前有刷新任务正在执行,则忽略
*/
fun tryRefresh()
fun networkStatusChange(status: Boolean)
fun addTokenRefreshListener(listener: TokenRefreshListener)
fun removeTokenRefreshListener(listener: TokenRefreshListener)
fun reset()
interface TokenRefreshListener {
fun onNewToken(token: Token)
}
}
服务端流程
- 所有接入在线教室的机构均需要在开发者中心注册,注册通过后会分配唯一的 AppID 和应用 AppSecret,作为机构身份标识以及后续认证使用
- 当机构注册完成,并且完成了相关的接入工作后,当机构用户需要访问在线教室相关服务和资源时,统一需要经过在线教室的认证服务认证后才可访问,一旦认证失败或者Token过期,在线教室会返回相关错误码
- 机构客户端需要能响应该错误码并且重新向机构自己服务端签发新的Token
- 机构客户端携带新的Token再次访问教室服务和资源,在线教室认证服务验证通过,放行用户或者返回相关资源,完成请求
JSON Web Token
JWT 由三部分组成,每个部分通过 . 分隔:header.payload.verify_signature
在线教室 Payload 信息
{
"aid": 1234, // 应用 ID
"user_id": 2137382639302388928, // 用户信息
"role_key": "group_teacher", // 角色信息
"issued_at": 1836717482, // 签发时间
"expires_at": 1852941882 // 过期时间
}