[原]关于单点登录中的用户信息存储问题的探讨
因为项目中使用了单点登录,用户信息的存储应该重新被审视,这就是书写本篇文章的原因。
项目中没有涉及用户注册的功能,用户信息但是对于企业应用来说,注册是必须的,同时也涉及到cas server到哪个数据源验证的问题(是cas server的,还是cas client的),所以对于这个问题来说说自己的点点见解。
方案一:Cas Server端提供注册功能并维护用户通用信息,Cas Client端维护用户详细信息。
Cas Server端建一个集中注册和维护的用户信息库,仅存放通用信息,例如身份证号、员工编号、姓名和口令等等,CAS在此用户库上进行集中认证。可以用一个LDAP服务器,如ActiveDirectory来集中管理这个用户信息库。
当用户通过CAS验证访问客户端应用时,CAS传递用户凭证(身份证号、员工编号、姓名),客户端须判断该用户凭证是否在本系统中存在,如果已存在则自动进入系统,并遵循客户端权限管理;
如果用户凭证在客户端应用中没有保存过,则根据业务需要判断CAS提供的用户通用信息是否足够用,若够用直接后台写入本系统用户表,然后进入系统;如果还需补充其它信息则弹出注册页面,显示通用信息,用户补充填入其它信息后提交,这样用户下次再访问本系统时就可以自动进入。
像QQ的应用,你登录时,就是手机、邮箱、密码这类通用的信息,这些信息就保存在CASServer端。进入各应用后,再完善扩展信息,如工作经验、性别、地区等,这个就好比QQ里微博信息的完善,像QQ校友里的学校的设置等等。
如果用户在业务系统中原本就有账户信息(在单点登录系统实施前的旧系统),则在上诉注册页面让用户选择绑定原有账户,输入原客户端应用的登录名和登录口令,验证通过后将用户的CAS凭证和旧账户绑定保存在客户端用户表中,这样用户再次访问客户端应用时就可以使用原账户的相关信息。
对于注册功能,CAS提供基于 Rest-APi 的登录、验证、注销;
这样的话,用户登录某一应用(CAS中的Client端)时,会被拦截,转到Server端,在Server端读数据库进行验证,验证通过后,返回到Client端,然后Client端再根据username读自己的数据库,取出用户的信息(因为各个Client的用户实体的属性是不一样的,比如有的Client端的用户有手机号这一属性,有的则没有,所以综合了一下,最好只在Server端存用户的用户名和密码,这应该也是Cas Server默认只向CasClient传递username的原因)。
方案二:Server端无DB,注册时到各Client端只把用户信息保存到各自的DB
其实针对多个用户信息不同表情况继承原有系统时是比较常见的。
但这就存在两个问题:
用户信息问题
系统A a_user
系统B b_user
假如a_user中有一个用户:auser,b_user中有一个用户buser,这样你无论用哪一个用户登录,CAS就会先查a_user,如果用户名密码都正确,那么就通过,如果a_user中验证失败,那么CAS就会再查b_user,用户名密码都正确就算通过了,此时不正确,就算这次登录验证没通过。
这种验证方法不大适合,如果有N个子应用系统,那么就意味有 N个user表,一次登录,可能需要 select n次。
同时也违背了CAS 的原则,本身就是一个统一认证服务中心,为什么还要在各自应用系统提供用户验证接口。
本项目中就存在这个问题,Cas Server没有DB,用户表分布在Cas Client:权限系统有权限系统的用户表,基础系统有学生、教师、用户等多张表。
权限管理问题
当用户A单点登录到B系统时候那么B系统对A用户的权限验证问题(B系统中没有A的用户信息,是否需要数据同步)如何处理。
针对这个问题,本项目是通过权限系统作为中间件来解决这个问题的,即所有权限放在权限系统,当CAS验证通过后,各个cas client到权限系统读取并缓存操作权限的。
这样的话,用户登录某一应用(CAS中的Client端)时,会被拦截,转到Server端,Server端根据请求的不同判断该调用哪个Client的DB进行验证,此处又要有分支了:
1)、验证的时候把用户信息读出来,验证通过后,将用户信息直接传给Client端,这样Client端就不用再读DB提取用户信息了。
2)、验证的时候不读用户的信息,验证通过后,返回到Client端,Client端再读用户信息。
小结
非常提倡方案一的做法:Cas Server端提供注册功能并维护用户通用信息,Cas Client端维护用户详细信息。腾讯等大型网站就是这样做的。
而方案二:Server端无DB,注册时到各Client端只把用户信息保存到各自的DB。其实已经把Cas Server架空了,但这种应用在整合旧系统时用的比较多。