怎麼實現單一登入系統?以下這篇文章跟大家介紹一下使用node實作單一登入系統的方法,希望對大家有幫助!
單一登入SSO(Single Sign On),就是把2個以上的業務系統中的登入功能剝離出來,形成一個新的系統,做到一次登入後在任意的業務系統中都無需登入的效果。
來源= 協議網域名稱連接埠
以http://www.a.com為例:
相同策略是瀏覽器的行為,它透過確保應用程式下的資源只能被本應用程式訪問,來保證安全。 【相關教學推薦:nodejs影片教學】
由於http協定是無狀態協定(客戶端和伺服器端資料交換完畢,會關閉連接,下次請求重新建立連接),但我們需要做記住密碼等功能時,很明顯需要將會話記錄下來。
常用的會話追蹤就是cookie和session,簡單的理解它們就是可以存放key,value的資料結構,差別在於cookie保存在客戶端,session保存在伺服器端。
同父網域,如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' }})
當我們的網域為www.a .com
,www.b.com
時,無論怎樣設定domain都沒用了。
那麼就要想辦法將身分憑證(token)寫入到所有網域的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>
但是我們可以透過標籤發起跨域請求,寫入cookie
<script></script>
或使用jquery jsonp的方式發起跨域請求,寫入cookie,這種方式的原理也是透過標籤能夠跨域實現的。
$.ajax({ url: 'https://www.c.com:3000/sso?key=username&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) => { 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錯誤封包error Error: Cannot send secure cookie over unencrypted connection 這我覺得是koa框架寫cookie的限製吧,它只能支援https寫cookie…,於是我把www.c.com改為了https伺服器.
router.get('/sso', async (ctx, next) => { 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'})
访问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.query let token = "123"; ctx.response.redirect(`${from}?token=${token}`)})
www.a.com上从url上获取token,存入cookie
router.get('/createCookie', async (ctx, next) => { let { token } = ctx.request.query ctx.cookies.set('token', token, { maxAge: 60 * 60 * 1000, //有效时间,单位毫秒 httpOnly: false, path: '/', }); ctx.body = 'set cookie ok'})
这样就实现了跨域信息的传递.与上面的方式不同,这种方法只是单纯的http请求,适用于所有浏览器,但是缺点也很明显,每次只能分享给一个服务器。
之前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) => { let username = ctx.cookies.get('username') console.log('cookie', username)})
可以看到读取到了存储在www.a.com里面domain为www.c.com的cookie.
效果如图所示:
第一次访问www.a.com首页
跳转到www.c.com:3000登录页面,登录成功后跳转www.a.com首页
再次访问www.a.com首页,无需登录直接跳转
访问www.b.com首页,无需登录直接跳转
源码: https://github.com/wantao666/sso-nodejs
详细设计:
更多node相关知识,请访问:nodejs 教程!
以上是淺析node怎麼實現單一登入系統的詳細內容。更多資訊請關注PHP中文網其他相關文章!