基于NODEJS的SSO登录方案

一、前言

注册、登录是服务端常做的功能,主要涉及用户信息表单提交、会员信息保存、登录状态维护,前端除了表单提交外也没有什么可参与的,能发挥的作用很少。

如果通过nodejs介入开发,则可参与更多,这也是为什么建议大家学习下nodejs,通过服务端语言来增强自己的技术栈,技术研发是一个综合类的能力,相比较Java,单纯依靠前端是难以支撑技术的体量,这也是前端人员发展后期所面临的尴尬,若以前端为主体,知晓服务端、数据库、运维、测试等技术栈,则能支撑更宽更深的技术体量。

前段时间为公司项目提供了sso解决方案,这里分享下。

二、误区

登录重点在于会员状态的维护、保持,初级者有两个误区

  • 使用数据库保持登录状态

即收到用户登录信息后,将状态维护在数据库,这样是可行的,但效率是非常低,因为后续每次涉及到用户权限的页面、数据获取都需要先验证状态,通过数据库操作耗时

  • 单纯使用session

这算不上一个误区,也是教程常用的方式,不过session通常是保存在当前服务的缓存里的,单台服务可行,但多台服务器集群时,session无法共享

基于上面两种情况,我们需要一个可被多台服务器快速访问的独立服务 -- redis。memcache也可达到,不过相比之下,redis功能、稳定性都更好。

登录实现

前后端分离时我采用了下图的架构,可参考 全栈技术栈

全栈架构图

前后端分离架构中登录流程

分离架构中流程如下

前后端分享时的登录流程

用户在client输入username + password,提交到Node服务,Node对数据做规则有效性验证,错误则返回,通过则发给java到DB做信息验证,会员信息有效,由java端生成sessionId,通过http-header-cookie,由nodejs保存到客户端的cookie里,同时由java将sessionId保存到独立的缓存服务器redis里,以sessionId为key,可以多保存一些不适合保存在客户端的信息,如权限。

当客户端请求用户数据时,http会自动带上cookie,nodejs检查是否有sessionId,如无,或在redis里不存在,则返回错误或redirect到login.html,若有,则继续请求java,通常任何一个涉及到用户信息的请求,无论是renderView,还是fetchData,都需要验证,所以需要频繁的获取验证,此时redis的缓存读取效率更高。

用户退出时,由nodejs清空cookie,及redis里的sessionId,即可。

SSO实现

浏览器出于安全考虑,实现了同源策略,对于跨站请求可以使用jsonp或设置http的Access-Control-Allow-Origin实现跨域。

同源策略对cookie的访问限制,造成不同域无法相互访问(二级域名可以访问主域)。所以若A/B两个不同域名的站点,使用同一套会员体系,也无法同时登录(如baidu.com / hao123.com),而实际项目中我们需要处理这样的问题,即会员A站登录后,打开B站也要保持该会员的登录状态,我的实现见下图

SSO实现

A/B两站,分别有客户端和服务端,单站登录的客户端与服务端的通信见前图,此处不在描述,涉及跨站的流程大致如下

会员在A站登录,A站服务端生成sessionId外,再额外生成一个ticket,设置3s时效,以请求返回值的形式返回给客户端,如下,同时,将ticket以{ticket: sid}形式保存在redis里

#返回值
{
   code: 0,
   message: 'signin success',
   data: {ticket:'ffqwoij1230340lklfdf123fklk'
}

A站客户端收到返回后,请求B站的链接,如

B.com/api/auth.gif?ticket=ffqwoij1230340lklfdf123fklk

B站服务端收到该请求后,获取该ticket,到redis内验证该ticket存在,且取到sessionid,再将sessionid,通过http-header-cookie输出到B站客户端的cookie里,即为B添加的会员状态的标识。同时删除redis里的ticket。

A/B站都使用了同一个sid,且保存在同一个redis里,所以任何一方因退出而清空redis.sessionid的操作,都会引起其它站点的退出。

注意以下几点:

  • A站收到ticket后,马上发出B站的请求做登录验证,间隔时间很短,3S通常是够了,设置时效性,也更安全

  • ticket的生成需要加入请求的客户端信息,以便数据被拦截后在其它环境非法登录,如IP等信息

  • 发向B站的请求,通常有图片、iframe两种形式,后者过重,图片形式较轻。

思考该方案时参考了百度的实现,也只是参考了其发图片请求这一点,其内部的机制并不了解,加上自己的思考实现这一套方案,且用于公司的项目上。

若需要两个以上的域名登录,处理相同。

百度登录

参见百度的实现,可以看到其发出了多个crossdomain请求,每个都是向不同的域发出的请求,如hao123.com、anquanbao.com等

Node.js基于token的登录验证是一种常见的身份验证和授权机制。它使用令牌作为凭据来验证用户身份并授权访问受保护的资源。 当用户登录成功后,服务器会生成一个token。这个token是一个随机字符串,它包含了一些用户信息和相关权限。服务器将这个token发送给客户端,客户端将其保存在本地,如localStorage或cookie中。 当用户访问需要身份验证的资源时,客户端将token作为请求头或请求参数发送给服务器。服务器接收到请求后,会解析token并验证其有效性。若token有效且未过期,则认为用户已登录,可以授权用户访问受保护的资源。否则,服务器会返回未授权的错误响应。 优点: 1. 无状态:服务器不需要保存用户的登录状态,因此可以更好地扩展和分布式。 2. 安全性:通信过程中token被加密和签名,使其难以伪造和改变。 3. 高效性:验证过程简单,减少了服务器的负载。 4. 可扩展性:可以轻松地用于支持多个客户端和API。 缺点: 1. 客户端存储:客户端需要存储token,如果被盗用或泄露,可能会导致安全风险。 2. 无法废止tokens:一旦发出的token被盗用,服务器无法废止,除非过期时间到期或用户进行密码重置。 总之,基于token的登录验证是一种简单且高效的身份验证和授权机制,适用于大多数Web应用程序。但在实施时,必须注意安全风险,例如使用HTTPS来确保通信安全,并定期更新token以减少盗用的风险。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值