认证与授权协议对比:OAuth2、OpenID、SMAL 以及OIDC

认证(authenticate)授权(authorize)是俩个容易被弄混的概念,尤其是只看英文。

认证意味着证实某个用户是他所声明的那个人;授权意味决定一个身份确定的用户能够访问哪些资源。

认证授权是目前大多数系统都必须要实现的功能,认证就是验证用户的身份,授权就是验证身份后对受限资源的访问控制。最开始是单个平台要做,后来在互联网时代到来,一个账户可登陆多个平台,然后是各种开放平台账户共享,认证授权变得越来越重要。关于验证授权方面的规范协议也相对成熟通用。

单店登录和统一认证中主要三个协议是OpenIDOAuthSAML被称为单点登录的三驾马车。

最早出现的认证授权协议是SMAL,一般用在企业级单点登录场景。平时接触到的不多。

OAuth是看到的用的比较多的认证协议,尤其是在API认证授权时用,最开始是1.0版本,后来因为有会话共计、会话劫持的漏洞,除了1.0a版本,但编程实现较麻烦,后来出现OAuth2版本,但不兼容之前的版本。一般见到大多数时用的是OAuth2.

OpenId一开始出现是为了解决认证的问题,后来出现了OpenId Connect,在OAuth的基础上也可以实现授权的功能。

对比点 OAuth2 OpenId SMAL
票据格式 JSON or SAML2 JSON XML
支持授权 Yes No Yes
支持认证 伪认证 Yes Yes
创建年份 2005 2006 2001
最新版本 OAuth2 OpenID Connect SAML2.0
传输方式 HTTP HTTP GET and HTTP POST HTTP重定向,SAML SOAP绑定 ,HTTP POST绑定
安全弱点 不能抵抗网络钓鱼,OAyth没有使用数据签名和加密等措施,数据安全完全依赖TLS 不能抵抗网络钓鱼,一个钓鱼的IDP如果恶意记录下来用户的OpenID,将会造成很严重的隐私安全问题。 XML签名存在漏洞,可能被伪造。
使用场景 API授权 商用应用的单店登录 企业级的单店登录,但是对于移动端支持不是很好。

SAML2.0协议

SAML,全称为Security Assertion Markup Language,是一种用于安全性断言的标记语言,目前最新版本是2.0。

SAML在单点登录中大有用处:在SAML协议中,一旦用户身份被主网站(身份鉴别服务器,Identity Provider,IDP)认证过后,该用户再去范文其他在主网站注册过的应用(服务提供者,Service Providers,SP)时,都可以直接登录,而不用在输入身份和口令。

SAML协议的核心是:IDP和SP通过用户的浏览器的重定向访问来实现交换数据。

SP向IDP发出SAML身份认证请求消息,来请求IDP鉴别用户身份;IDP向用户索要用户名和口令,并验证其是否正确,如果验证无误,则想SP返回SAML身份认证应答,表示该用户已经登录成功了,此外应答中还包括一些额外的信息,来确保应答不被篡改和伪造。

下面我们以用户登录SP,SP向IDP发起求情来确认用户身份微粒子,看看SAML的工作流程。比如SP是Google的Apps,IDP是一所大学的身份服务器,Alice是该大学的一名学生。

SAML认证流程

现在Alice要通过浏览器查阅她的邮件,Alice一般会通过浏览器访问一个网页,比如https://mail.google.com/a/my-university.nl.因为这是个联合身份域,所以Google不会向用户索取用户名和密码,而是将其重定向到IDP来认证其身份。用户被重定向的URL类似于这种:

https://idp:uni.nl/sso?SAMLRequest=fVLLTuswEN0j8Q...C%3D

嵌入到HTTP请求中的SAMLRequest就是SAML认证请求消息。因为SAML是基于XML的(通常比较长),完整认证求情消息要经过压缩(为Url节省空间)和编码(防止特殊字符)才能传输。在压缩和编码之前,SAML消息有如下格式:

<AuthnRequest  ID="kfcn...lfki" 
  Version="2.0" 
  IssueInstant="2013-02-05T08:28:50Z" 
  ProtocolBinding="urn:oasis:names:tc:SAML: 2.0:bindings:HTTP-POST" 
  ProviderName="google.com" 
  AssertionConsumerServiceURL="https://www.google.com/a/uni.nl/acs">
  <Issuer>google.com</Issuer>
  <NameIDPolicy  AllowCreate="true"
    Format="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified"/>;
</AuthnRequest>;

上面的内容用最直白的方式解释出来就是:这个来自Google的求情,请验证当前用户身份,并将结果返回

当IDP收到消息并确认要接受认证求情之后,就会要求Alice输入用户名和口令来验证其身份(如果Alice已经登陆过了,就会跳过该步骤);当验证通过之后,Alice的浏览器将会跳转回google的特定页面(AssertionConsumerService 简称ACS)。同样,SAML身份认证响应的内容也是在压缩并编码后以参数形式传输。在压缩和编码之前,其结构如下:

<Response Version="2.0" 
  IssueInstant="2013-02-05T08:29:00Z" 
  Destination="https://www.google.com/a/my.uni.nl/acs" InResponseTo="kfcn...lfki">   
  <Issuer>https://idp.uni.nl/</Issuer>   
  <Status>
    <StatusCode   
      Value="urn:oasis:names:tc:SAML:2.0:status:Success"/> 
  </Status> 
  <Assertion Version="2.0" 
    IssueInstant="2013-02-05T08:29:00Z">     
    <Issuer>https://idp.uni.nl/</Issuer>   
    <Subject> 
      <NameID>alice</NameID>   
      <SubjectConfirmation ...> 
        <SubjectConfirmationData 
          NotOnOrAfter="2013-02-05T08:34:00Z"   
          Recipient="https://www.google.com/a/my.uni.nl/acs" InResponseTo="kfcn...lfki"/>  
        </SubjectConfirmation> 
    </Subject> 
    <Conditions NotBefore="2013-02-05T08:28:30Z" NotOnOrAfter="2013-02-05T08:34:00Z"> 
    </Conditions> 
    <AuthnStatement 
      AuthnInstant="2013-02-05T08:29:00Z" 
      SessionNotOnOrAfter="2013-02-05T16:29:00Z> 
    </AuthnStatement> 
  </Assertion>
 </Response>

虽然内容很多,但是其主要表达的是:该消息来自idp.uni.nl,名为Alice的用户身份已经被我验证,该消息的有效期分2分钟,此外重定向的URL中还要有该消息的签名以保证其不被篡改,验证签名的公钥和算法,都是IDP和SP提前协商好的。

当Google接受到SAML认证相应之后,会首先验证消息的签名是否正确以及是否超时失效,然后再从认证消息中提取出Google能识别用户身份(NameId 即Alice)如果以上的步骤都是顺利的,用户将会成功登陆Google。

为了便于解释,以上例子中的信息都保持可读性,如果想要去看看真实的SAML信息,建议使用火狐浏览器的插件工具SAML tracer。该插件将会在浏览器中添加一个窗口来显示SAML消息,一下是截图。


SAML tracer

参考

https://www.jianshu.com/p/636c1ee16eba


OAuth2.0协议

协议中的各种角色:应用、API和用户

  • 第三方应用:客户端。即尝试去获得用户账户信息的应用,用户需要先对此操作授权。
  • API:资源服务器,提供用来获得用户信息的API。
  • 授权服务器:让用户同意或者拒绝访问请求。在某些情况下,授权服务器和API资源服务器会是同一个,但是在大多数情况下,二者是独立的。
  • 用户:资源的拥有者,当前请求正在尝试获得他们账户的部分信息。

创建App

在开始OAuth流程之前,首先需要注册一个新应用到服务器。通常在注册的过程中,需要提供应用的基本信息,比如应用名称、网站信息、logo等等。此外,你还需要注册一个重定向URI,用以将用户通过浏览器或者移动客户端重定向回Web服务器,这个URI很重要。

重定向URI

服务器只会把用户重定向回注册过的URI以避免有些安全攻击。任何HTTP的重定向请求都必须会用TLS保护,所以要求使用HTTPS。这样的要求是为了防止token在传输过程中被截获。对于原生APP,重定向的URI可以被注册为一个自定义的URL scheme,比如:

demoapp://redirect
Client ID & Secret

当注册完毕之后,一般会返回给用户一个客户端ID(Client ID)和一个客户端秘钥(Client Secret)。这个ID一般是公开的信息,用来构造登录URL,或者被包含在页面的JS代码中。这个秘钥必须是保密的。如果一个已经部署的应用不能保护秘钥,比如一个简单的JS网页,则不应该使用客户端秘钥,同时理论上服务器也不应该向这类应用颁发秘钥。

授权 得到授权码

OAuth2 流程的第一步是获得用户的授权。对于基于浏览器应用或是移动应用,这一步通常是在服务器显示给用户的接口上完成的。

OAuth2 提供了多种授权模式,根据不同情况而使用。

  • 授权码模式:适用于web应用,浏览器应用或是移动APP
  • 口令模式:适用于使用用户名和口令登录的模式
  • 应用访问模式:适用于应用访问
  • 默认模式:之前被推荐,在没有Secret的情况下使用,现在被没有客户端秘钥的授权码模式取代

Web 服务

Web服务是最常见的应用类型。用户所使用的Web App程序运行在服务器端,其源码不会公开暴露,这就代表着这类应用在授权的过程中可以使用客户端秘钥(Client Secret),以避免某些攻击手段。

授权

创建登录链接,将用户重定向到授权服务器:

https://oauth2server.com/auth?response_type=code&
 client_id=CLIENT_ID&redirect_uri=REDIRECT_URI&scope=photos&state=abcdef
  • code:代表服务器希望收到授权码
  • client_id:注册应用时颁发的ID
  • redirect_uri:指明当用户授权完成之后返回的地址;
  • scope:一个或多个值,用来指明希望获得用户账户哪部分权限;
  • state:由应用生成的一个随机字符串,会在之后的过程中去验证。

通过以上链接,用户将看到如下的界面


IDP的授权页面

当用户点击allow后,授权服务器会把用户重定向回应用网站,并在连接中带上授权码

https://oauth2client.com/cb?code=AUTH_CODE_HERE&state=abcdef
  • code:IDP服务器返回的授权码
  • state:返回请求授权码过程中发送的state

当应用有接收到这个请求时,要首先验证state是否就是应用刚才发送的值。在发送state之后,可以吧state保存到Session以便于后序的比较。这样做的目的是防止应用接受任意伪造的授权码。

换取Token

然后使用授权码到资源服务器换取Token

POST https://api.oauth2server.com/token
  grant_type=authorization_code&
  code=AUTH_CODE_HERE&
  redirect_uri=REDIRECT_URI&
  client_id=CLIENT_ID&
  client_secret=CLIENT_SECRET
  • grant_type = authorization_code :代表授权模式为授权码模式
  • code = AUTH_CODE_HERE:为上一步code中获取的授权码
  • redirect_uri = REDIRECT_URI 重定向URI
  • client_id = CLIENT_ID 注册应用时颁发的ID
  • client_secret=CLIENT_SECRET 客户端秘钥,因为当前请求是服务器之间的传输,并没有暴露给用户。

IDP服务器会返回授权码和有效期:

{
  "access_token":"RsT5OjbzRn430zqMLgV3Ia",
  "expires_in":3600
}

或者是授权失败的提示

{
  "error":"invalid_request"
}

注意:服务器要求应用必须提前注册重定向的URI


口令模式

这种模式直接使用用户名和密码来取回token。很显然,这种应用去手机用户的口令,所以之间以当前的App是专门为服务器设计的情况下使用。

POST https://api.oauth2server.com/token
  grant_type=password&
  username=USERNAME&
  password=PASSWORD&
  client_id=CLIENT_ID
  • grant_type=password 指明使用口令模式
  • username=USERNAME 用户名
  • password=PASSWORD 口令
  • client_id=CLIENT_ID client

资源服务器返回的Token和其他模式一样。值得注意的是,因为口令模式多用于移动端和桌面应用,使用secret并不合适。


应用访问模式

在一些情况下,是应用去访问服务器获取资源。而不是某个用户。比如应用去获取一些服务在应用的配置信息,这些信息不属于某个用户的。这种情况下,应用也需要被授权,得到Token去访问数据,这就是应用访问模式的意义。
Oauth提供了Client_credentials模式来处理这个问题:

POST https://api.oauth2server.com/token
    grant_type=client_credentials&
    client_id=CLIENT_ID&
    client_secret=CLIENT_SECRET

资源服务器返回形式和其他模式是相同的。

创建已经授权的请求

最后就是使用AccessToken获取资源,如何表示一个请求已经被授权?就是在Http头中加入Token:

curl -H "Authorization: Bearer RsT5OjbzRn430zqMLgV3Ia" \
https://api.oauth2server.com/1/me

另外尽量确保使用Https通信,这样才能保证信息安全。

与OAuth1.0版本差异

最后说明下两个版本OAuth协议有什么不同点。

认证和签名

OAuth1.0流程中有大量密码学上的签名操作,以保证数据完整性;OAuth2 由Https来保护数据。

用户体验

和OAuth 1.0相比,OAuth 2在移动端的体验更好。

性能

和OAuth 1.0相比,OAuth 2性能更好,减少了流程的步骤。

这里有一份很好理解的图解:
【简易图解】『 OAuth2.0』 猴子都能懂的图解
【简易图解】『 OAuth2.0』 『进阶』 授权模式总结

参考

https://www.jianshu.com/p/6392420faf99


OpenID Connect协议

如果要谈单点登录和身份认证,就不得不谈OpenID Connect(OIDC).最典型的使用实例就是使用Google账户登陆其他应用,这一经典的协议模式,为其他厂商的第三方登陆起到了标杆的作用。被广泛参考和使用。

OpenID Connect简介

OpenID Connect是基于OAuth2 规范族的客户操作的身份验证协议。他是用简单的REST/JSON 消息流来实现,和之前任何一种身份认证协议相比,开发者可以轻松集成。

OpenID Connect允许开发者验证跨网站和应用的用户,而无需拥有和管理密码文件。
OpenID Connect允许索尼又类型的客户,包括基于浏览器的JavaScript和本机移动应用程序,启动登录流动和接收可验证断言对登录用户的身份。

OIDC基础

简要而言,OIDC是一种安全机制,用于应用连接到身份认证服务器(Identity Service)获取用户信息,并将这些信息以安全可靠的方法返回给应用。

在最初因为OpenID经常和OAuth协议一起提及,所以二者经常被搞混。

  • OpenID 是Authentication,即认证,对用户的身份进行认证,判断其身份是否有效,也就是让网站知道“你是你声称的那个用户”
  • OAuth是Authorization 即授权,在已知用户身份合法的情况下,经用户授权来允许某些操作,也就是让网站知道“你能被允许做哪些事情”
    由此可知,授权要在认证之后进行,只有确定用户身份之后才能授权

(身份认证)+OAuth2.0 = OpenID Connect

OpenID Connect是“认证”和“授权”的结果,因为其基于OAuth协议,所以OpenID Connect协议中包含了client_id、client_secret还有redirect_uri等字段标识。这些信息被保存在“身份认证服务器”,以确保特定的客户端收到的信息只来自于合法的应用平台。这样做的目的是为了防止client_id泄露而造成的恶意网站发起的OIDC流程。

举个栗子,某个用户使用FaceBook的子应用(例如faceBook中的某一款游戏),该应用可以通过FaceBook账号登录,则你可以在应用找那个发起请求到“身份认证服务器”(也就是FaceBook的服务器)请求登录,这时你会看到如下界面,询问是否授权。

授权页面

在OAuth中,这些授权被称为scope.OpenID Connect也有自己特殊的scope--openid,他必须在第一次请求“身份鉴别服务器(Identity Provider简称IDP)”时发送过去。

OIDC 流程

OAuth2提供了Access Token来解决授权单方客户端访问受保护资源的问题;相似的,OIDC在这个基础上提供了ID Token来解决第三方客户端表示用户身份认证的问题。
OIDC的核心在于OAUth2的授权流程中,一并提供用户的身份认证信息(ID-Token),给到第三方客户端,ID-Token使用JWT(JSON Web Token - 在Web应用间安全地传递信息
)格式来包装,得益于JWT的自包含性,紧凑型以及防篡改机制,是的ID-Token可以安全的传递给第三方客户端程序并且容易被验证。应用服务器,在验证ID-Token正确性后,使用Access-Token向UserInfo接口换取用户的更多信息。

有上述可知,OIDC是遵循了OAuth协议流程,在申请Access-Token的同时,也返回了ID-Token来验证用户身份。

相关定义
  • EU:End User 用户。
  • RP:Relying Party 用来代指OAuth2中受信任的客户端,身份认证和授权信息的消费方。
  • OP:OpenID Provider,有能力提供EU身份认证的服务方(比如OAuth2中的授权服务),用来为RP提供EU的身份认证信息。
  • ID-Token:JWT格式的数据,包含EU身份认证的信息。
  • UserInfo EndPoint:用户信息接口(受IAuth2保护),当RP使用ID-Token访问时,返回授权用户的信息,此接口必须使用HTTPS。

下面我们来俺看OIDC的具体协议流程。
根据应用客户端不同,OIDC的工作模式月应该是不同的。和OAuth类似,主要看是否客户端能否保证client_secret的安全性。

如果是JS应用,其所有的代码都会被加载到浏览器而暴露出来,没有后端可以保证client_secret的安全性,则需要使用默认模式流程(Implicit Flow)

如果是传统的客户端应用,后端代码和用户是隔离的保证client_secret不被泄漏。就可以使用授权码模式流程(Authentication Flow).

此外还有混合模式流程(Hybird Flow),简而言之就是以上二者的融合。

OAuth2中还有口令模式和应用访问模式 这两种方式来获取access Token,为什么OIDC中没有扩展这些方式呢?
口令模式是需要用户提供账号和密码给RP的,既然都已经有用户名和密码了,就不需要再获取什么用户身份了。至于应用访问模式,这种方式不需要用户参与,也就无需要认证和获取用户身份了。这也能反映出授权和认证的差异,以及只是用OAuth2来做身份认证的事情是远远不够的,也是不合适的。

授权码模式流程

授权码模式流程

和OAuth认证流程类似
1.RP发送一个认证请求给OP,其中附带client_id
2.OP对EU进行身份认证
3.OP返回响应,发送授权码给RP
4.RP使用授权码想OP索要ID-Token和Access-Token,OP验证无误后返回给RP;
5.RP使用Access-Token发送一个请求到UserInfo EndPoint;UserInfo EndPoint返回EU的Claims。

基于Authorization Code的认证请求

RP使用OAth2的Authorization-code的方式来完成用户身份认证,所有TOken都是通过OP的Token EndPoint来发放的。构建一个OIDC的Authentication Request需要提供如下参数:

  • scope:必须。OIDC的请求必须包含值为“openid”的scope参数。
  • response_type: 必选 同OAuth2
  • client_id: 必选。同OAuth2
  • redirect_uri:必选。同OAuth2
  • state:推荐 同OAuth2.防止CSRF,XSRF。

示例如下:

GET /authorize?
    response_type=code
    &scope=openid%20profile%20email
    &client_id=s6BhdRkqt3
    &state=af0ifjsldkj
    &redirect_uri=https%3A%2F%2Fclient.example.org%2Fcb HTTP/1.1
  Host: server.example.com

基于Authorization Code的认证请求的响应

在OP接收到认证请求之后,需要对请求参数做严格的验证,具体的规则参见http://openid.net/specs/openid-connect-core-1_0.html#AuthRequestValidation,验证通过后引导EU进行身份认证并且同意授权。在这一切都完成后,会重定向到RP指定的回调地址(redirect_uri),并且把code和state参数传递过去。比如:

HTTP/1.1 302 Found
  Location: https://client.example.org/cb?
    code=SplxlOBeZQQYbYS6WxSbIA
    &state=af0ifjsldkj

获取ID Token

RP使用上一步获得的code来请求TOken EndPoint,这一步同OAuth2,就不再展开细说了。然后Token EndPoint会返回响应的Token,其中除了OAuth2规定的部分数据外,还会附加一个id_token字段,就是上面提到的ID Token。例如:

  HTTP/1.1 200 OK
  Content-Type: application/json
  Cache-Control: no-store
  Pragma: no-cache

  {
   "access_token": "SlAV32hkKG",
   "token_type": "Bearer",
   "refresh_token": "8xLOxBtZp8",
   "expires_in": 3600,
   "id_token": "eyJhbGciOiJSUzI1NiIsImtpZCI6IjFlOWdkazcifQ.ewogImlzc
     yI6ICJodHRwOi8vc2VydmVyLmV4YW1wbGUuY29tIiwKICJzdWIiOiAiMjQ4Mjg5
     NzYxMDAxIiwKICJhdWQiOiAiczZCaGRSa3F0MyIsCiAibm9uY2UiOiAibi0wUzZ
     fV3pBMk1qIiwKICJleHAiOiAxMzExMjgxOTcwLAogImlhdCI6IDEzMTEyODA5Nz
     AKfQ.ggW8hZ1EuVLuxNuuIJKX_V8a_OMXzR0EHR9R6jgdqrOOF4daGU96Sr_P6q
     Jp6IcmD3HP99Obi1PRs-cwh3LO-p146waJ8IhehcwL7F09JdijmBqkvPeB2T9CJ
     NqeGpe-gccMg4vfKjkM8FcGvnzZUN4_KSP0aAp1tOJ1zZwgjxqGByKHiOtX7Tpd
     QyHE5lcMiKPXfEIQILVq0pc_E2DzL7emopWoaoZTF_m0_N0YzFC6g6EJbOEoRoS
     K5hoDalrcvRYLSrQAZZKflyuVCyixEoV9GfNQC3_osjzw2PAithfubEEBLuVVk4
     XUVrWOLrLl0nx7RkKU8NXNHq-rvKMzqg"
  }

其中看起来一堆乱码的部分就是JWT格式的ID-Token。在RP拿到这些信息之后,需要对id_token以及access_token进行验证(具体规则参见http://openid.net/specs/openid-connect-core-1_0.html#IDTokenValidationhttp://openid.net/specs/openid-connect-core-1_0.html#ImplicitTokenValidation)。至此,可以说用户身份认证就可以完成了。后序可以根据UserInfo EndPoint获取更完整的信息。

安全令牌 ID-Token

上面提到过OIDC对OAuth2最主要的扩展就是提供了ID-Token,下面我们来看看ID-Token的主要构成:

  • iss = Issuer Identifier:必须。提供认证信息者的唯一标识。一般是Url的host+path部分
  • sub = Subject Identifier:必须。iss提供EU的唯一标识;最长为255个ASCII个字符;
  • aud = Audience(s):必须。标识ID-Token的受众。必须包含OAuth2的client_id;
  • exp =Expiration time:必须。ID-Token的过期时间。
  • iat = Issued At Time。必须。JWT构建的时间。
  • auth_time = AuthenticationTime:EU完成认证的时间。如果RP发送认证请求的时候携带max_age的参数,则此Claim是必须的。
  • nonce:RP发送请求的时候提供的随机字符串,用来减缓重放攻击,也可以来关联ID-Token和RP本身的Session信息。
  • acr = Authentication Context Class Reference:可选。表示一个认证上下文引用值,可以用来标识认证上下文类。
  • amr = Authentication Methods References:可选。表示一组认证方法。
  • azp = Authorized party:可选。结合aud使用。只有在被认证的一方和受众(aud)不一致时才使用此值,一般情况下很少使用。
{
   "iss": "https://server.example.com",
   "sub": "24400320",
   "aud": "s6BhdRkqt3",
   "nonce": "n-0S6_WzA2Mj",
   "exp": 1311281970,
   "iat": 1311280970,
   "auth_time": 1311280969,
   "acr": "urn:mace:incommon:iap:silver"
  }

另外ID Token必须使用JWT进行签名和JWE(JSON Web Encryption)加密。从而提供认证的完整性、不可否认性以及可选的保密性。

USerInfo EndPoint

可能有的读者发现了,ID-Token只有sub是EU相关的,这在一般情况下是不够的,必须还需要EU的用户名,头像等其他的资料,OIDC提供了一组公共的cliams,来提供更多用户的信息,这就是UserInfo EndPoint。

在RP得到Access Token后可以请求此资源,然后获得一组EU相关的Claims,这些信息可以说是ID-Token的扩展,ID-Token中只需包含EU的唯一标识sub即可(避免ID-Token过于庞大和暴露用户敏感信息),然后再通过此接口获取完整的EU的信息。此资源必须部署在TLS之上(即必须使用HTTPS)例如:

  GET /userinfo HTTP/1.1
  Host: server.example.com
  Authorization: Bearer SlAV32hkKG

成功之后响应如下:

  HTTP/1.1 200 OK
  Content-Type: application/json

  {
   "sub": "248289761001",
   "name": "Jane Doe",
   "given_name": "Jane",
   "family_name": "Doe",
   "preferred_username": "j.doe",
   "email": "janedoe@example.com",
   "picture": "http://example.com/janedoe/me.jpg"
  }

其中sub代表EU的唯一标识,这个claim是必须的,其他都是可选的。

参考

https://www.jianshu.com/p/be7cc032a4e9

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342

推荐阅读更多精彩内容