溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

基于Go語(yǔ)言實(shí)現(xiàn)的單點(diǎn)登錄系統(tǒng)

發(fā)布時(shí)間:2020-06-23 20:10:20 來(lái)源:網(wǎng)絡(luò) 閱讀:15829 作者:二郎神六號(hào) 欄目:軟件技術(shù)

參考:https://jwt.io/introduction/

該單點(diǎn)登錄是基于Go語(yǔ)言實(shí)現(xiàn)的單點(diǎn)登錄系統(tǒng),下面先簡(jiǎn)單介紹JWT

JSON Web Token簡(jiǎn)述

JWT是一個(gè)開(kāi)放的標(biāo)準(zhǔn)(RFC 7519),它定義了一個(gè)緊湊且自包含的方式,用于在各方之間以JSON對(duì)象安全地傳輸信息.這些信息可以通過(guò)數(shù)字簽名進(jìn)行驗(yàn)證和信任??梢允褂妹孛埽ㄊ褂肏MAC算法)或使用RSA的公鑰/私鑰對(duì)來(lái)對(duì)JWT進(jìn)行簽名。

緊湊:由于它們尺寸較小,JWT可以通過(guò)URL,POST參數(shù)或HTTP頭內(nèi)發(fā)送。另外,尺寸越小意味著傳輸速度越快。

自包含:有效載荷包含有關(guān)用戶的所有必需信息,避免了多次查詢數(shù)據(jù)庫(kù)的需要。

JSON Web Token 應(yīng)用場(chǎng)景

身份驗(yàn)證(Authentication):這是使用JWT最常見(jiàn)的情況。一旦用戶登錄,每個(gè)后續(xù)請(qǐng)求將包括JWT,允許用戶訪問(wèn)該令牌允許的路由,服務(wù)和資源。單點(diǎn)登錄是目前廣泛使用JWT的一項(xiàng)功能,因?yàn)樗拈_(kāi)銷很小,而且能夠輕松地在不同的域中使用。

信息交換:JSON Web Tokens是在各方之間安全傳輸信息的好方法。因?yàn)镴WT可以被簽名,例如使用公鑰/私鑰對(duì),所以你可以確定發(fā)件人是他們說(shuō)的那個(gè)人。此外,由于使用標(biāo)頭、有效載荷、計(jì)算簽名,因此您還可以驗(yàn)證內(nèi)容是否未被篡改。

JWT 結(jié)構(gòu)

JSON Web Tokens包含三個(gè)由點(diǎn)(.)分隔的部分,它們是:頭部、有效載荷、簽名
JWT通??雌饋?lái)如下所示。
xxxxx.yyyyy.zzzzz

Header頭部

頭部通常由兩部分組成:令牌的類型(即JWT)和正在使用的散列算法(the hashing algorithm 如HMAC SHA256或RSA)。
例如:
{
"alg": "HS256",
"typ": "JWT"
}
然后,這個(gè)JSON被Base64Url編碼,形成JWT的第一部分。

有效載荷

令牌的第二部分是包含聲明的有效載荷。 聲明是關(guān)于實(shí)體(通常是用戶)和附加元數(shù)據(jù)的聲明。 有三種類型的聲明:保留,公開(kāi)和私有聲明。

保留的聲明(Reserved claims):這是一組預(yù)先定義的聲明,不是強(qiáng)制性的,但推薦使用,以提供一組有用的,可互操作的聲明。 其中一些是:iss(發(fā)行人),exp(到期時(shí)間),sub(主題),aud(聽(tīng)眾)等等。

    請(qǐng)注意,聲明名稱只有三個(gè)字符長(zhǎng),因?yàn)镴WT是緊湊的。

公開(kāi)聲明(Public claims):這些可以由使用JWT的人員任意定義。 但為避免沖突,應(yīng)在IANA JSON Web令牌注冊(cè)表中定義它們,或者將其定義為包含防沖突命名空間的URI。

私有聲明(Private claims):這是為了同意使用它們的各方之間共享信息而創(chuàng)建的自定義claims。

有效載荷的一個(gè)例子可以是:
{
"sub": "1234567890",
"name": "John Doe",
"admin": true
}
然后將有效載荷Base64Url進(jìn)行編碼,以形成JSON Web令牌的第二部分。

簽名

要?jiǎng)?chuàng)建簽名部分,您必須采用編碼頭部,編碼有效載荷,密鑰,頭部中指定的算法并簽名。

例如,如果您想使用HMAC SHA256算法,簽名將按以下方式創(chuàng)建:
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
secret)
簽名用于驗(yàn)證JWT的發(fā)件人是誰(shuí),并確保郵件在一路上沒(méi)有改變。

拼接在一起

輸出是三個(gè)由點(diǎn)分隔的Base64字符串,可以輕松地在HTML和HTTP環(huán)境中傳遞,而與基于XML的標(biāo)準(zhǔn)(如SAML)相比,它更加緊湊。
下面顯示了一個(gè)JWT,它具有先前的頭部和有效載荷編碼,并且用秘密簽名。
基于Go語(yǔ)言實(shí)現(xiàn)的單點(diǎn)登錄系統(tǒng)

JSON Web Token如何工作

在身份驗(yàn)證中(authentication),當(dāng)用戶使用他們的憑證(credentials)成功登錄時(shí),將返回一個(gè)JSON Web Token,并且必須保存在本地(通常在本地存儲(chǔ)中,但也可以使用Cookie),而不是在傳統(tǒng)方法中創(chuàng)建會(huì)話 服務(wù)器并返回一個(gè)cookie。

無(wú)論何時(shí)用戶想要訪問(wèn)受保護(hù)的路由或資源,用戶代理都應(yīng)發(fā)送JWT,通常在Authorization頭部的Bearer模式中。 頭部的內(nèi)容應(yīng)該如下所示:
Authorization: Bearer <token>

這是一種無(wú)狀態(tài)身份驗(yàn)證機(jī)制,因?yàn)橛脩魻顟B(tài)永遠(yuǎn)不會(huì)保存在服務(wù)器內(nèi)存中。 服務(wù)器的受保護(hù)路由將在授權(quán)頭中檢查有效的JWT,如果存在,則允許用戶訪問(wèn)受保護(hù)的資源。 由于JWT是獨(dú)立的,所有必要的信息都在那里,減少了多次查詢數(shù)據(jù)庫(kù)的需求。

這使您可以完全依賴無(wú)狀態(tài)的數(shù)據(jù)API,甚至向下游服務(wù)發(fā)出請(qǐng)求。 無(wú)論哪個(gè)域正在為您的API提供服務(wù),跨源資源共享(CORS)將不會(huì)成為問(wèn)題,因?yàn)樗皇褂胏ookie。

下圖顯示了這個(gè)過(guò)程:
基于Go語(yǔ)言實(shí)現(xiàn)的單點(diǎn)登錄系統(tǒng)

為什么我們應(yīng)該使用JWT

讓我們來(lái)談?wù)勁c簡(jiǎn)單Web令牌(SWT)和安全聲明標(biāo)記語(yǔ)言令牌(SAML)相比,JSON Web令牌(JWT)的好處。

由于JSON不如XML冗長(zhǎng),所以在進(jìn)行編碼時(shí),它的大小也會(huì)變小,從而使JWT比SAML更緊湊。這使得JWT成為在HTML和HTTP環(huán)境中傳遞的一個(gè)很好的選擇。

安全方面,SWT只能通過(guò)使用HMAC算法的共享秘密進(jìn)行對(duì)稱簽名。但是,JWT和SAML令牌可以使用X.509證書(shū)形式的公鑰/私鑰對(duì)進(jìn)行簽名。與簽署JSON的簡(jiǎn)單性相比,使用XML數(shù)字簽名簽署XML而不引入模糊的安全漏洞是非常困難的。

JSON解析器在大多數(shù)編程語(yǔ)言中都很常見(jiàn),因?yàn)樗鼈冎苯佑成涞綄?duì)象。相反,XML沒(méi)有自然的文檔到對(duì)象映射。這使得使用JWT比SAML斷言更容易。

關(guān)于使用情況,JWT在互聯(lián)網(wǎng)上使用。這突出顯示了在多個(gè)平臺(tái)(尤其是移動(dòng)平臺(tái))上JSON Web令牌的客戶端處理的簡(jiǎn)易性。

Go語(yǔ)言實(shí)戰(zhàn)項(xiàng)目代碼

支持手機(jī)號(hào)碼+驗(yàn)證碼、郵箱+驗(yàn)證碼、微信第三方授權(quán)三種方式注冊(cè)
支持手機(jī)號(hào)碼、用戶名、郵箱號(hào)碼、微信登錄
支持手機(jī)和郵箱找回密碼
支持阿里云通信和互億無(wú)線的短信驗(yàn)證碼服務(wù)

代碼路徑:https://github.com/KenmyZhang/single-sign-on
package api

import (
    "net/http"
    "regexp"        
    "strconv"
    "fmt"
    l4g "github.com/alecthomas/log4go"

    "github.com/KenmyZhang/single-sign-on/app"
    "github.com/KenmyZhang/single-sign-on/model"
    "github.com/KenmyZhang/single-sign-on/utils"
    "github.com/KenmyZhang/single-sign-on/sqlStore"
)

func InitUser() {
    l4g.Debug(utils.T("api.user.init.debug"))
    BaseRoutes.User.Handle("", ApiCustomClaimsRequired(getUser)).Methods("GET")
    BaseRoutes.User.Handle("/image", ApiHandler(getProfileImage)).Methods("GET")
    BaseRoutes.User.Handle("/image", ApiCustomClaimsRequired(setProfileImage)).Methods("POST")      
    BaseRoutes.Users.Handle("/login", ApiHandler(login)).Methods("POST")
    BaseRoutes.Users.Handle("/logout", ApiHandler(logout)).Methods("POST")
    BaseRoutes.Users.Handle("/sendsms", ApiHandler(sendSmsCode)).Methods("POST")
    BaseRoutes.Users.Handle("/phone/signup", ApiHandler(signupByMobile)).Methods("POST")
    BaseRoutes.Users.Handle("/phone/login", ApiHandler(loginByMobile)).Methods("POST")
    BaseRoutes.Users.Handle("/phone/exist", ApiHandler(isMobileExist)).Methods("POST")
    BaseRoutes.Users.Handle("/phone/reset", ApiHandler(resetPasswordByMobile)).Methods("POST")
    BaseRoutes.Users.Handle("/email/verify/code/send", ApiHandler(sendVerificationCodeEmail)).Methods("POST")
    BaseRoutes.Users.Handle("/email/signup", ApiHandler(signupByEmail)).Methods("POST")
    BaseRoutes.Users.Handle("/email/exist", ApiHandler(isEmailExist)).Methods("POST")
    BaseRoutes.Users.Handle("/email/reset", ApiHandler(resetPasswordByEmail)).Methods("POST")
    BaseRoutes.Users.Handle("/search", ApiCustomClaimsRequired(searchUsers)).Methods("POST")
}

    ......

推薦一篇文章
https://www.cnblogs.com/lyzg/p/6132801.html
https://studygolang.com/articles/11793

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI