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的博客
欢迎关注个人公众号:「程序那些事」最通俗的解读,最深入的干货,最简洁的教程,众多你不知道的小技巧等你来发现!