前后端分离场景下的另类登录认证方案
在我们日常开发中,通常会接入第三方的登录,比如QQ、微信、微博等。在公司内部,也会介入公司的内网登录。通常情况下,我们的方案是:
当应用检测到没有用户信息时,就会跳转到(302)第三方服务,用户在第三方服务登录后返回应用时会带上用户的信息(Session),这就是一般情况下我们的登录认证过程。
在前后端分离的场景下,一般做法是中间层(Node)检查用户请求的Header中是否存在用户信息,如果不存在则向第三方服务请求认证(302),认证成功后返回当前的登录用户的信息,再进行其他业务逻辑的处理。
既然标题有另类一词,我们肯定不能局限于“一般做法”。在我们的前后端分离场景中,由Node充当中间层,Java提供HTTP Restful接口,我们场景不同点在于第三方服务(通常是集团登录认证服务)不支持Node接口,只提供Java接口。所以我们必须通过 Node去请求Java,由Java去请求认证服务然后返回Node。方案如下:
看上面流程图,我们的方案不过是在Node和Auth Server中增加了Java Server,并没有其他异处。只因这个方案和一般前后端分离场景的认证不太一样,里面的需要注意的细节较多,可以记录一下。
首先是用户通过url的输入,访问页面的过程,流程如下:
讲解之前注意:
在我们的场景中:
Node与Java Web的Ajax要么带有效cookie,要么带tickets(一次有效)。
我们的页面是 http://localhost
浏览器通过url访问Node服务器(即页面请求),Node会检测用户的请求里面是否带有用户信息的Cookie。如果没有,则向Java Web发出用户信息的请求,由于没有有效cookie,Java Web判定当前用户未登录,返回 {code:302, url: xxx}
。Node接收到302后,直接 redirect 到刚才的url上。这个url通常是: http://www.xxx.com?redirect=http://localhost
用户在Home(第三方登录认证服务)完成登录过程后,会返回我们的localhost,并且带有tickets: http://localhost?tickets=asdfasdfasdfasdf。
第二次,我们又回到了页面请求的步骤,同理Node检测不到用户请求中的用户信息有效Cookie,会向Java Web出用户信息的请求,不同之处在于会带上刚才Home返回的url上的tickets。Java Web发现请求中没有cookie但是有tickets,于是拿着tickets去向Home认证,此tickets是否有效,有效Home会返回用户信息,Java Web存储此用户信息并且返回给Node。Node拿到用户信息后,立即往response里面写入用户cookie,同时redirect到/(作用是,去掉url上的tickets)。
第三次浏览器向Node发出页面请求,由于Node检测到请求中有cookie,就会直接返回页面给浏览器。之后用户的所有行为操作的ajax请求,都会带上cookie,所以都是合法的。
思考:
上面认证方案中,其实只需要发出两次页面请求,也就是访问两次 localhost。我们第三次redirect的原因是,去掉url的tickets。如果不去掉也没有影响,但是会出现用户手动去刷新页面的情况,手动刷新页面的tickets是不可用的,java会返回403,影响用户使用。
总结:
我们的认证登录方案,和传统的方案并无差别,不过多了中间Node和Java的交互而已。需要注意的就是cookie的写入时机和tickets的去除。