jwt是什么?
jwt是一种session
信息存储方案,单点登录和是否用jwt没关系,jwt也是和系统内的流程一致,不一样的地方就是将session数据放到了前端。JWT 的最大缺点是,由于服务器不保存 session 状态,因此无法在使用过程中废止某个 token,或者更改 token 的权限。也就是说,一旦 JWT 签发了,在到期之前就会始终有效,除非服务器部署额外的逻辑。
是否有CSRF风险?
有。
- 可以加
Access-Control-Allow-Origin
来控制可以跨域请求的页面 - 跳回到子系统的时候,后台可以返回
token
,所有请求都需要带上token
验证。
优化空间
登录成功后现在是访问authority/user/redirect
由后端进行302跳转到子系统redirect
路由。这是因为之前到方案是需要后台写cookie到子系统,直接跳转到子系统页面上。改成了现在这样。但是依照现在的方案的话,没有必要再走一次302.直接在登录接口返回ticket,由前端带上ticket
直接访问子系统的redirect
路由,该路由再返回html
,执行location.href=
要跳往的路径。可以少一次302跳转,减少loading时长。
cookie有同源策略,为什么不同域名访问cookie对应domain时都会携带上该cookie?
对cookie同源策略理解有问题,cookie的同源策略指的是访问不同域的资源时,浏览器允不允许携带cookie,和当前页面域名没有关系。比如A域名下访问了B域名的接口,会带上B域名下的cookie,但不会带上C域名下的cookie。
为什么需要单点登录?
- 用户希望登录一个系统后,登录其他系统不想再登录一遍。
- 而且在私有化部署时,各子域需要部署各自的登录模块。前后端代码都是用的各自的,不便于维护。
-
chrome
、firefox
等浏览器支持第三方cookie,ie
和safari
不支持。这就导致我们不能共用一个登录域下的cookie。
单点登录的整体流程
子系统融合时各系统获取登录态的问题
之前公司各个子系统各自独立,公司发展,同事客户也希望购买多个产品时,应该只有一个系统而不需要私有化部署多套系统。
系统融合时,原来的计划是融合后的菜单中,子菜单中为各个子系统,子系统内的请求还是走各自的系统的接口。出现的问题是在统一的登录中心登录完成跳回到系统时(此时写cookie到系统域名下),如果请求不同菜单(也就是不同子系统中的服务),会出现请求不同域导致后台无法获取到种在当前系统下的cookie,后台也就无法判断当前用户是否登录。
业内常见的做法是登录成功后写入到主域下,各个子系统分别在各子域中,这样子域就能拿到主域的cookie,因为我们的系统是私有化部署,使用时都是ip,也就不存在主域的概念。无法使用这个办法,另外一个办法后台写cookie时,httponly设为false,由前端来获取到当前域下写入的cookie,请求不同子系统时作为参数带上。不过这样安全性就会降低。
目前的做法还是走反向代理,走统一的接口地址,由后台来转发各子系统下的请求,统一前缀来作区分。
在登录中心登录成功后如何写cookie到子系统域名下?
方案一:
- 前端重定向到子系统,带上登录成功后下发的ticket,子系统前端请求后台,将该ticket带上。
- 后台拿到该ticket后调用authority进行校验。如果成功就写登录cookie到子系统域名下。
- 子系统拿到请求结果再渲染对应资源。这种方式简单,但有个缺点是每个子系统接入都得重写一遍该逻辑。
方案二:
- 约定一个固定的子系统跳转地址,各子系统后台接入sdk 后,每个请求都会先经过该sdk,sdk监听该固定地址。
- 在登录中心登录成功后,前端请求authority下的一个地址,返回结果为302,并且写cookie到登录中心域名下,重定向地址为子系统下的固定地址,并带上ticket。
- sdk监听到该请求后,再次返回302 重定向地址到子系统真实页面,并将ticket写入到子系统cookie中。(这里不能返回302,在各浏览器中同时返回302和cookie不能写入成功,项目中的解决方案是状态码还是为200,资源返回html,由html中js来做跳转)
- nginx则转发到对应的机器目录下,返回对应的静态资源。
当一个子系统登录成功后,直接访问另外一个子系统,发生了什么?
首先会直接拿到前端资源并发起请求,如果请求响应为登录失效,则前端跳转页面到登录中心某一地址,【注意】这时候的请求就会带上登录中心页面的cookie,后台校验发现cookie有效,那么会返回302响应,戴上ticket跳回之前约定好的子系统固定地址,sdk监听到该请求后如果ticket有效,那么就回到方案二中的步骤3,最后跳回到子系统。