您好,登錄后才能下訂單哦!
今天小編給大家分享一下node如何實現單點登錄系統的相關知識點,內容詳細,邏輯清晰,相信大部分人都還太了解這方面的知識,所以分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后有所收獲,下面我們一起來了解一下吧。
源 = 協議 + 域名 +端口
以http://www.a.com為例:
https://www.a.com ?(協議不同)
http://www.b.com ?(域名不同)
http://www.a.com:3000 ?(端口不同)
同源策略是瀏覽器的行為,它通過確保應用下的資源只能被本應用訪問,來保證安全。
由于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>
但是我們可以通過< script />標簽發起跨域請求,寫入cookie
<script src="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.
后端
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報錯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.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利用< 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
<script src="https://www.c.com:3000/readCookie"></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首頁,無需登錄直接跳轉
詳細設計:
以上就是“node如何實現單點登錄系統”這篇文章的所有內容,感謝各位的閱讀!相信大家閱讀完這篇文章都有很大的收獲,小編每天都會為大家更新不同的知識,如果還想學習更多的知識,請關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。