nodejs如何实现单点登录系统
导读:本文共4913字符,通常情况下阅读需要16分钟。同时您也可以点击右侧朗读,来听本文内容。按键盘←(左) →(右) 方向键可以翻页。
摘要: 单点登录SSO(Single Sign On),就是把2个及以上的业务系统中的登录功能剥离出来,形成一个新的系统,做到一次登录后在任意的业务系统中都无需登录的效果。一. 基础知识1.1 同源策略源 = 协议 + 域名 +端口以http://www.a... ...
目录
(为您整理了一些要点),点击可以直达。
单点登录SSO(Single Sign On),就是把2个及以上的业务系统中的登录功能剥离出来,形成一个新的系统,做到一次登录后在任意的业务系统中都无需登录的效果。
一. 基础知识
1.1 同源策略
源 = 协议 + 域名 +端口
以http://www.a.com为例:
https://www.a.com ❌(协议不同)
http://www.b.com ❌(域名不同)
http://www.a.com:3000 ❌(端口不同)
同源策略是浏览器的行为,它通过确保应用下的资源只能被本应用访问,来保证安全。
1.2 会话机制
由于http协议是无状态协议(客户端和服务器端数据交换完毕,会关闭连接,下次请求重新建立连接),但我们需要做记住密码等功能时,很明显需要将会话记录下来。【相关教程推荐:nodejs视频教程】
常用的会话跟踪就是cookie和session,简单的理解它们就是可以存放key,value的数据结构,区别在于cookie保存在客户端,session保存在服务器端。
二. 单点登录
1. 同父域SSO
同父域,如www.app1.aaa.com
,www.app2.aaa.com
这两个服务器都是在.aaa.com的父域名。
默认情况下,两个服务器下页面之间的cookie是互相访问不到的。
但是我们可以通过设置cookie的domain属性为共通的父域名,使得两个服务器下页面之间的cookie可以相互访问到。
router.get('/createCookie',async(ctx,next)=>{ctx.cookies.set('username','123',{maxAge:60*60*1000,httpOnly:false,path:'/',domain:'.a.com'//设置domain为共通的父域名});ctx.body="createcookieok"})router.get('/getCookie',async(ctx,next)=>{letusername=ctx.cookies.get('username')if(username){ctx.body=username}else{ctx.body='nocookie'}})
2. 跨域SSO
当我们的域名为www.a.com
,www.b.com
时,无论怎样设置domain都没用了。
那么就要想办法将身份凭证(token)写入到所有域的cookie中。
2.1 跨域写cookie
在http://www.a.com/index.js中直接向https://www.c.com:3000/sso直接发送网络请求,是无法跨域写入cookie的。
<script>$.ajax({url:'https://www.c.com:3000/sso?key=username&value=123',method:'get',})</script>
但是我们可以通过< script />标签发起跨域请求,写入cookie
<scriptsrc="https://www.c.com:3000/sso?key=username&value=123"></script>
或者使用jquery jsonp的方式发起跨域请求,写入cookie,这种方式的原理也是通过< script />标签能够跨域实现的。
$.ajax({url:'https://www.c.com:3000/sso?key=username&value=123',method:'get',dataType:'jsonp'})
这样通过< script />标签就实现了往www.a.com中写入了domain为www.c.com的跨域cookie.
后端
constoptions={key:fs.readFileSync(path.join(__dirname,'./https/privatekey.pem')),cert:fs.readFileSync(path.join(__dirname,'./https/certificate.pem')),secureOptions:'TLSv1_2_method'//forceTLSversion1.2}varserver=https.createServer(options,app.callback());//只能使用https协议写cookierouter.get('/sso',async(ctx,next)=>{let{key,value}=ctx.request.queryctx.cookies.set(key,value,{maxAge:60*60*1000,//有效时间,单位毫秒httpOnly:false,//表示cookie是否仅通过HTTP(S)发送,,且不提供给客户端JavaScript(默认为true).path:'/',sameSite:'none',//限制第三方Cookiesecure:true//cookie是否仅通过HTTPS发送});ctx.body='createCookieok'})
注意:
浏览器未写入cookie报错
his set-cookie was blocked due to http-only
http-only:表示 cookie 是否仅通过 HTTP(S) 发送,, 且不提供给客户端 JavaScript (默认为 true).
所以要将httpOnly设置为false.浏览器未写入cookie报错
this set-cookie was blocked due to user preference
这个真的坑,因为我是无痕模式打开的浏览器,但是chrome浏览器默认无痕模式下禁用第三方cookie,修改为允许所有cookie就行了.浏览器未写入cookie报错
this set cookie was blocked because it has the SameSite attribute but Secure not set
需要设置sameSite和secure属性浏览器未写入cookie报错
server error Error: Cannot send secure cookie over unencrypted connection
这个我觉得是koa框架写cookie的限制吧,它只能支持https写cookie…,于是我把www.c.com改为了https服务器.
上面说的jsonp的方式在chrome浏览器中完美运行,但是IE浏览器对于cookie更加严格,只用上面方式无法写入cookie,解决办法就是加上p3p的响应头。
router.get('/sso',async(ctx,next)=>{let{key,value}=ctx.request.queryctx.cookies.set(key,value,{maxAge:60*60*1000,//有效时间,单位毫秒httpOnly:false,path:'/',sameSite:'none',secure:true});ctx.set("P3P","CP='CURaADMaDEVaPSAoPSDoOURBUSUNIPURINTDEMSTAPRECOMNAVOTCNOIDSPCOR'")//p3p响应头ctx.body='createCookieok'})
访问http://www.c.com:3000/createToken?from=http://www.a.com/createCookie
www.c.com上生成token后将url重写,带上token,重定向到www.a.com
router.get('/createToken',async(ctx,next)=>{let{from}=ctx.request.querylettoken="123";ctx.response.redirect(`${from}?token=${token}`)})
www.a.com上从url上获取token,存入cookie
router.get('/createCookie',async(ctx,next)=>{let{token}=ctx.request.queryctx.cookies.set('token',token,{maxAge:60*60*1000,//有效时间,单位毫秒httpOnly:false,path:'/',});ctx.body='setcookieok'})
这样就实现了跨域信息的传递.与上面的方式不同,这种方法只是单纯的http请求,适用于所有浏览器,但是缺点也很明显,每次只能分享给一个服务器。
2.2 跨域读cookie
之前2.1.1利用< script />标签在www.a.com中写入了www.c.com的cookie(username,123),现在想要www.a.com请求的时候携带上www.c.com的cookie,也就是说要跨域读cookie.
其实也是同样的方法,在www.a.com上利用< script />跨域访问访问www.c.com,会自动的带上domain为www.c.com的cookie。www.a.com/index.js
<scriptsrc="https://www.c.com:3000/readCookie"></script>
www.c.com
router.get('/readCookie',async(ctx,next)=>{letusername=ctx.cookies.get('username')console.log('cookie',username)})
可以看到读取到了存储在www.a.com里面domain为www.c.com的cookie.
3. nodejs实现单点登录系统实战
效果如图所示:
第一次访问www.a.com首页
跳转到www.c.com:3000登录页面,登录成功后跳转www.a.com首页
再次访问www.a.com首页,无需登录直接跳转
访问www.b.com首页,无需登录直接跳转
详细设计:
</div> <div class="zixun-tj-product adv-bottom"></div> </div> </div> <div class="prve-next-news">
nodejs如何实现单点登录系统的详细内容,希望对您有所帮助,信息来源于网络。