登录  /  注册
首页 > web前端 > js教程 > 正文

什么是单点登录系统?用nodejs怎么实现?

青灯夜游
发布: 2023-02-24 19:33:33
转载
1927人浏览过

什么是单点登录系统?用nodejs怎么实现?下面本篇文章给大家介绍一下使用node实现单点登录系统的方法,希望对大家有所帮助!

什么是单点登录系统?用nodejs怎么实现?

单点登录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 = "create cookie ok"})router.get('/getCookie', async (ctx, next) => {
  let username=ctx.cookies.get('username')
  if (username){
    ctx.body=username  }else{
    ctx.body='no cookie'
  }})
登录后复制

在这里插入图片描述

2. 跨域SSO

当我们的域名为www.a.com,www.b.com时,无论怎样设置domain都没用了。

那么就要想办法将身份凭证(token)写入到所有域的cookie中

2.1 跨域写cookie
2.1.1 利用标签跨域写cookie(jsonp)

在http://www.a.com/index.js中直接向https://www.c.com:3000/sso直接发送网络请求,是无法跨域写入cookie的。

  <script>
    $.ajax({
      url: &#39;https://www.c.com:3000/sso?key=username&value=123&#39;,
      method: &#39;get&#39;,
    })
  </script>
登录后复制

但是我们可以通过标签发起跨域请求,写入cookie

<script></script>
登录后复制
登录后复制

或者使用jquery jsonp的方式发起跨域请求,写入cookie,这种方式的原理也是通过标签能够跨域实现的。

 $.ajax({
      url: 'https://www.c.com:3000/sso?key=username&amp;value=123',
      method: 'get',
      dataType:'jsonp'
    })
登录后复制

这样通过标签就实现了往www.a.com中写入了domain为www.c.com的跨域cookie.
在这里插入图片描述
后端

const options = {
  key: fs.readFileSync(path.join(__dirname, './https/privatekey.pem')),
  cert: fs.readFileSync(path.join(__dirname, './https/certificate.pem')),
  secureOptions: 'TLSv1_2_method' //force TLS version 1.2}var server = https.createServer(options,app.callback());  //只能使用https协议写cookierouter.get('/sso', async (ctx, next) =&gt; {
  let {
    key, value  } = ctx.request.query
  ctx.cookies.set(key, value, {
    maxAge: 60 * 60 * 1000, //有效时间,单位毫秒
    httpOnly: false, //表示 cookie 是否仅通过 HTTP(S) 发送,, 且不提供给客户端 JavaScript (默认为 true).
    path: '/',
    sameSite: 'none', //限制第三方 Cookie
    secure: true //cookie是否仅通过 HTTPS 发送
  });
  ctx.body = 'create Cookie ok'})
登录后复制

注意:

  • 浏览器未写入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服务器.

2.1.2 p3p协议头实现IE浏览器跨域

上面说的jsonp的方式在chrome浏览器中完美运行,但是IE浏览器对于cookie更加严格,只用上面方式无法写入cookie,解决办法就是加上p3p的响应头。

router.get('/sso', async (ctx, next) =&gt; {
  let {
    key, value  } = ctx.request.query
  ctx.cookies.set(key, value, {
    maxAge: 60 * 60 * 1000, //有效时间,单位毫秒
    httpOnly: false,
    path: '/',
    sameSite: 'none',
    secure: true
  });
  ctx.set("P3P", "CP='CURa ADMa DEVa PSAo PSDo OUR BUS UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR'") //p3p响应头
  ctx.body = 'create Cookie ok'})
登录后复制
2.1.3 url参数实现跨域信息传递

访问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) =&gt; {
  let { from } = ctx.request.query  let token = "123";
  ctx.response.redirect(`${from}?token=${token}`)})
登录后复制

www.a.com上从url上获取token,存入cookie

router.get('/createCookie', async (ctx, next) =&gt; {
  let { token } = ctx.request.query
  ctx.cookies.set('token', token, {
    maxAge: 60 * 60 * 1000, //有效时间,单位毫秒
    httpOnly: false,
    path: '/',
  });
  ctx.body = 'set cookie ok'})
登录后复制

这样就实现了跨域信息的传递.与上面的方式不同,这种方法只是单纯的http请求,适用于所有浏览器,但是缺点也很明显,每次只能分享给一个服务器。
在这里插入图片描述

2.2 跨域读cookie
2.2.1 利用标签跨域读cookie(jsonp)

之前2.1.1利用标签在www.a.com中写入了www.c.com的cookie(username,123),现在想要www.a.com请求的时候携带上www.c.com的cookie,也就是说要跨域读cookie.

其实也是同样的方法,在www.a.com上利用跨域访问访问www.c.com,会自动的带上domain为www.c.com的cookie。
www.a.com/index.js

<script></script>
登录后复制
登录后复制

www.c.com

router.get('/readCookie', async (ctx, next) =&gt; {
  let username = 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首页,无需登录直接跳转

源码: https://github.com/wantao666/sso-nodejs

详细设计:
在这里插入图片描述

更多node相关知识,请访问:nodejs 教程

以上就是什么是单点登录系统?用nodejs怎么实现?的详细内容,更多请关注php中文网其它相关文章!

智能AI问答
PHP中文网智能助手能迅速回答你的编程问题,提供实时的代码和解决方案,帮助你解决各种难题。不仅如此,它还能提供编程资源和学习指导,帮助你快速提升编程技能。无论你是初学者还是专业人士,AI智能助手都能成为你的可靠助手,助力你在编程领域取得更大的成就。
来源:csdn网
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
作者最新文章
最新问题
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送
PHP中文网APP
随时随地碎片化学习
PHP中文网抖音号
发现有趣的

Copyright 2014-2024 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号