SSO是單點登陸的簡稱,經常使用的SSO的協議有兩種,分別是SAML和OAuth2。本文將會介紹兩種協議的不一樣之處,從而讓讀者對這兩種協議有更加深刻的理解。前端
SAML的全稱是Security Assertion Markup Language, 是由OASIS制定的一套基於XML格式的開放標準,用在身份提供者(IdP)和服務提供者 (SP)之間交換身份驗證和受權數據。java
SAML的一個很是重要的應用就是基於Web的單點登陸(SSO)。git
在SAML協議中定義了三個角色,分別是principal:表明主體一般表示人類用戶。identity provider (IdP)身份提供者和service provider (SP)服務提供者。github
IdP的做用就是進行身份認證,而且將用戶的認證信息和受權信息傳遞給服務提供者。web
SP的做用就是進行用戶認證信息的驗證,而且受權用戶訪問指定的資源信息。shell
接下來,咱們經過一個用SAML進行SSO認證的流程圖,來分析一下SAML是怎麼工做的。瀏覽器
上圖中User Agent就是web瀏覽器,咱們看一下若是用戶想請求Service Provider的資源的時候,SAML協議是怎麼處理的。安全
http://sp.flydean.com/myresource
SP將會對該資源進行相應的安全檢查,若是發現已經有一個有效的安全上下文的話,SP將會跳過2-7步,直接進入第8步。服務器
302 Redirect Location: https://idp.flydean.com/SAML2/SSO/Redirect?SAMLRequest=request&RelayState=token
RelayState是SP維護的一個狀態信息,主要用來防止CSRF攻擊。app
其中這個SAMLRequest是用Base64編碼的<samlp:AuthnRequest>,下面是一個samlp:AuthnRequest的例子:
<samlp:AuthnRequest xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" ID="aaf23196-1773-2113-474a-fe114412ab72" Version="2.0" IssueInstant="2020-09-05T09:21:59Z" AssertionConsumerServiceIndex="0" AttributeConsumingServiceIndex="0"> <saml:Issuer>https://sp.flydean.com/SAML2</saml:Issuer> <samlp:NameIDPolicy AllowCreate="true" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:transient"/> </samlp:AuthnRequest>
爲了安全起見,SAMLRequest還可使用SP提供的簽名key來進行簽名。
GET /SAML2/SSO/Redirect?SAMLRequest=request&RelayState=token HTTP/1.1 Host: idp.flydean.com
IdP收到這個AuthnRequest請求以後,將會進行安全驗證,若是是合法的AuthnRequest,那麼將會展現登陸界面。
<form method="post" action="https://sp.flydean.com/SAML2/SSO/POST" ...> <input type="hidden" name="SAMLResponse" value="response" /> <input type="hidden" name="RelayState" value="token" /> ... <input type="submit" value="Submit" /> </form>
這個form中包含了SAMLResponse信息,SAMLResponse中包含了用戶相關的信息。
一樣的SAMLResponse也是使用Base64進行編碼過的<samlp:Response>。
<samlp:Response xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" ID="identifier_2" InResponseTo="identifier_1" Version="2.0" IssueInstant="2020-09-05T09:22:05Z" Destination="https://sp.flydean.com/SAML2/SSO/POST"> <saml:Issuer>https://idp.flydean.com/SAML2</saml:Issuer> <samlp:Status> <samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/> </samlp:Status> <saml:Assertion xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" ID="identifier_3" Version="2.0" IssueInstant="2020-09-05T09:22:05Z"> <saml:Issuer>https://idp.flydean.com/SAML2</saml:Issuer> <!-- a POSTed assertion MUST be signed --> <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">...</ds:Signature> <saml:Subject> <saml:NameID Format="urn:oasis:names:tc:SAML:2.0:nameid-format:transient"> 3f7b3dcf-1674-4ecd-92c8-1544f346baf8 </saml:NameID> <saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer"> <saml:SubjectConfirmationData InResponseTo="identifier_1" Recipient="https://sp.flydean.com/SAML2/SSO/POST" NotOnOrAfter="2020-09-05T09:27:05Z"/> </saml:SubjectConfirmation> </saml:Subject> <saml:Conditions NotBefore="2020-09-05T09:17:05Z" NotOnOrAfter="2020-09-05T09:27:05Z"> <saml:AudienceRestriction> <saml:Audience>https://sp.flydean.com/SAML2</saml:Audience> </saml:AudienceRestriction> </saml:Conditions> <saml:AuthnStatement AuthnInstant="2020-09-05T09:22:00Z" SessionIndex="identifier_3"> <saml:AuthnContext> <saml:AuthnContextClassRef> urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport </saml:AuthnContextClassRef> </saml:AuthnContext> </saml:AuthnStatement> </saml:Assertion> </samlp:Response>
咱們能夠看到samlp:Response中包含有saml:Assertion信息。
咱們能夠看到上面的全部的信息交換都是由前端瀏覽器來完成的,在SP和IdP之間不存在直接的通訊。
這種所有由前端來完成信息交換的方式好處就是協議流很是簡單,全部的消息都是簡單的GET或者POST請求。
若是爲了提升安全性,也可使用引用消息。也就是說IdP返回的不是直接的SAML assertion,而是一個SAML assertion的引用。SP收到這個引用以後,能夠從後臺再去查詢真實的SAML assertion,從而提升了安全性。
SAML協議是2005年制定的,在制定協議的時候基本上是針對於web應用程序來講的,可是那時候的web應用程序仍是比較簡單的,更別提對App的支持。
SAML須要經過HTTP Redect和HTTP POST協議來傳遞用戶信息,而且一般是經過HTML FORM的格式來進行數據的提交的。若是應用程序並非web應用,好比說是一個手機App應用。
這個手機APP應用的啓動連接是 my-photos://authenticate , 可是手機app可能並不能獲取到Http POST的body內容。他們只可以經過URL來進行參數的傳遞。
這就意味着,在手機APP中不可以使用SAML。
固然,要想工做也能夠,不過須要進行一些改造。好比經過第三方應用對POST消息進行解析,而後將解析出來的SAMLRequest以URL參數的形式傳遞給APP。
另外一種方法就是使用OAuth2.
由於Oauth2是在2012年才產生的。因此並無那麼多的使用限制。咱們能夠在不一樣的場合中使用OAuth2。
咱們先來看一下OAuth2中受權的流程圖:
通常來講OAuth2中有4個角色。
resource owner: 表明的是資源的全部者,能夠經過提供用戶名密碼或者其餘方式來進行受權。一般來是一我的。
resource server:表明的是最終須要訪問到資源的服務器。好比github受權以後獲取到的用戶信息。
client: 用來替代resource owner來進行交互的客戶端。
authorization server: 用來進行受權的服務器,能夠生成相應的Access Token。
整個流程是這樣的:
Client向resource owner發起一個受權請求,resource owner輸入相應的認證信息,將authorization grant返回給client。
client再將獲取到的authorization grant請求受權服務器,並返回access token。
client而後就能夠拿着這個access token去請求resource server,最後獲取到受限資源。
OAuth2並無指定Resource Server怎麼和Authorization Server進行交互。也沒有規定返回用戶信息的內容和格式。這些都須要實現方本身去決定。
OAuth2默認是在HTTPS環境下工做的,因此並無約定信息的加密方式。咱們須要本身去實現。
最後,OAuth2是一個受權協議,而不是認證協議。對於這個問題,其實咱們能夠考慮使用OpenID Connect協議。由於OpenID Connect就是基於OAuth2實現的,而且添加了認證協議。
OpenID Connect簡稱爲OIDC,已成爲Internet上單點登陸和身份管理的通用標準。 它在OAuth2上構建了一個身份層,是一個基於OAuth2協議的身份認證標準協議。
OAuth2實際上只作了受權,而OpenID Connect在受權的基礎上又加上了認證。
OIDC的優勢是:簡單的基於JSON的身份令牌(JWT),而且徹底兼容OAuth2協議。
在SAML協議中,SAML token中已經包含了用戶身份信息,可是在OAuth2,在拿到token以後,須要額外再作一次對該token的校驗。
可是另外一方面,OAuth2由於須要再作一次認證,因此能夠在 Authorization Server 端對token進行無效處理。
作過SSO的應該都據說過CAS。CAS的全稱是Central Authentication Service,是一個企業級的開源的SSO認證框架。
CAS內部集成了CAS1,2,3,SAML1,2,OAuth2,OpenID和OpenID Connect協議,很是的強大。咱們會在後面的文章中介紹CAS的使用。
本文做者:flydean程序那些事本文連接:http://www.flydean.com/saml-vs-oauth2/
本文來源:flydean的博客
歡迎關注個人公衆號:「程序那些事」最通俗的解讀,最深入的乾貨,最簡潔的教程,衆多你不知道的小技巧等你來發現!