前言
不管是使用CS、BS,很多时候都是需要登录才能使用,这里面就涉及到了登陆授权、用户角色鉴权,以及数据隔离等功能。如果一家公司人员较多,角色较多,那么是十分需要这样一个登录权限控制系统的。内部系统繁多的公司更是如此,有个单点登录可以减少员工因为需要管理多账户而增加无为的工作量,降低员工为方便而增加账号泄露的风险。
在不同公司设计可能遇到不同的场景:
- 前端同域,后端同redis
- 前端不同域,后端同redis
- 前端同域,后端不同redis
- 前端不同域,后端不同redis
设计登录权限控制系统时,一般都是上面4个场景之一。如果要求高点,需要加入公司内部的 confluence、gitlab等系统,那可能还要考虑支持 OAuth2 协议、LDAP 等,但是这些都可以在基础版上做改造即可。
这里提供的是“前端不同域,后端不同redis”的基础版的登录权限控制系统设计思路。
交互时序图
设计说明
token
JWT
JWT第二部分是用户信息包含着4部分信息:
- 用户id(uid)
- 用户名称
姓名在贵公司属于敏感信息,可以采用英文名或者用户编码代替。 - 是否管理员
- 有效期
有效时长,单位:秒。
蜂拥登录
从交互时序图可以看到,用户登录校验通过后,需要获取用户信息生成token。这里有一个问题:如果是大型公司会存在一个时间点集中登录请求,那么很有可能出现蜂拥的现象。
可以通过以下手段优化:
- 限流
- 预登录机制
既然能预知蜂拥时间范围,那么可以提前加载部分用户数据 - 排队机制
- 增加节点
用户权限查询接口
用户、角色和菜单权限的关系如下图
如何设计才能快速判断用户是否有权限访问当前接口是关键。
一般调用方会传递 uid、path 和 method 给权限查询接口,如果想快速得到结果,那么缓存是一个不错的选择。如果直接缓存 uid + path + method,那么随着用户的增多,权限的增多,那么所需要的 redis 内存空间就越多。path 和 method 都是我们菜单权限配置在数据库里的记录,都会有唯一的id,如果将它们转成id,那么一个 uid 是否有权限访问某个接口的问题,就可以采用 Bitmap 来节省空间并且提升访问速度。
ps : 如果 uid 也十分多(几千,几万不算多),那么可以考虑将uid拼接上菜单id,然后采用稀疏位图来处理。
注意事项
有时需要通过异步线程去处理一些复杂的流程,以此提高系统的对用户请求的响应速度。异步线程需要获取用户信息,这种情况最好是自己传递或者设置 ThreadLocal,用完后自己清除线程变量,而不是去传递token。token里面本身就有用户信息,可以解析出来直接传递给异步线程。
常见问题
- 多系统接入,path 有相同的怎么办呢?
设计菜单权限时,角色和菜单都增加系统id,增加接入系统表即可。 - 如果登陆时要选择角色,不允许多角色登陆怎么处理?
获取用户权限那里,uid改成roteid即可。