OIDC

2023-03-21 14:35 星期二

协议概述

OIDC(OpenID Connect)是一个基于OAuth 2.0协议的身份认证标准协议,增加了 Id Token。

名词解释

  1. OpenID Provider(OP): OIDC 授权服务器,负责签发 ID Token。
  2. End-User(EU):用户,ID Token 的信息中会包含终端用户的信息。
  3. ID Token 由 OpenID Provider 颁发,包含关于终端用户的信息字段。
  4. UserInfo Endpoint:用户信息接口,通过 ID Token 访问时返回用户信息。
  5. Claims 指终端用户信息字段。

登录流程

  1. 用户尝试登录应用系统。
  2. 应用系统发送认证请求到OIDC 授权服务器。
  3. OIDC 授权服务器对用户进行认证与授权。
  4. OIDC 授权服务器返回认证信息,包含 ID Token、Access Token和Refresh Token。
  5. 应用系统获取认证信息后,再携带Access Token 发送请求到 UserInfo Endpoint。
  6. UserInfo Endpoint 返回 End-User 的 Claims。
  7. 应用系统验证End-User信息是否有效,有效则登录成功,反之失败。

开发详情

开发详情以授权码模式为例。
应用系统可以通过此接口获取 OIDC 授权服务器的基本配置信息。

HTTP Method:GET
https://demo.cloudentify.com/api/oauth/oidc/{appkey}/.well-known/openid-configuration              

返回示例:

{
    "issuer" : "https://test.cloudentify.com",
    "authorization_endpoint" : "https://test.cloudentify.com/api/oauth/authorize",
    "token_endpoint" : "https://test.cloudentify.com/api/oauth/token",
    "token_endpoint_auth_methods_supported" : [ "client_secret_basic"],
    "jwks_uri" : "https://test.cloudentify.com/api/oauth/oidc/{appkey}/.well-known/jwks.json",
    "response_types_supported" : [ "code" ],
    "grant_types_supported" : [ "authorization_code", "refresh_token" ],
    "subject_types_supported" : [ "public" ],
    "id_token_signing_alg_values_supported" : [ "RS256" ],
    "scopes_supported" : [ "openid","username","email","phone","address","profile","offline_access"]
}         

步骤1:

  • 获取用户授权,如果用户未登录系统,则要求用户进行身份认证(跳转至授权服务器进行认证),应用发起重定向至授权服务器的以下地址。接口支持 PKCE 模式,如需进行 PKCE 模式的校验,可传入相应的参数。
HTTP Method:GET
https://demo.cloudentify.com/api/oauth/authorize

请求参数:

  • client_id:必填,客户端 ID,从管理平台-应用管理-企业应用列表的App ID处获取;
  • response_type:必填,固定值“code”;
  • redirect_uri:必填,授权成功后的重定向地址;
  • state:非必填,应用系统提供的一个随机字符串,服务器会原样重定向给应用系统,防止 CSRF、XSRF;
  • scope:必填,参数值应以 openid 开头;
  • code_challenge_method:非必填,PKCE 模式的必要参数,即 code_challenge 值的计算方法,目前仅支持 SHA256;
  • code_challenge:非必填,PKCE 模式的必要参数,计算方式:code_challenge = code_challenge_method(code_verifier)。code_verifier 为校验码原文,应用系统需要自行保存code_verifier,并在获取授权令牌的请求中带上,用作验证,code_challenge_method使用SHA256。

请求示例:

https://demo.cloudentify.com/api/oauth/authorize?client_id=EFTDBB&response_type=code&redirect_uri=http%3A%2F%2Fwww.test.com&scope=openid%20phone%20profile%20offline_access%20email&code_challenge_method=S256&code_challenge=FWOeBX6Qw_krhUE2M0lOIH3jcxaZzfs5J4jtai5hOX4&state=123456
  • 授权服务器进行认证后,将通过redirect_uri传入的重定向地址,向应用下发授权码。
HTTP Method:GET
http://www.test.com?code=b9eb0dc233&state=123456

步骤2:

  • 应用获取到授权码后,使用授权码换取访问令牌。
HTTP Method:POST
https://demo.cloudentify.com/api/oauth/token

请求参数:

  • Authorization:必填,存放Header中, 接口鉴权值,Basic base64encode(client_id:client_secret);
  • grant_type:必填,固定值“authorization_code”;
  • redirect_uri:必填,授权成功后的重定向地址。如果“oauth/authorize”请求带有 redirect_uri 参数,则本步骤请求必须上送 redirect_uri 参数;
  • code:必填,授权码;
  • scope:必填,参数值应以 openid 开头;
  • code_verifier:非必填,PKCE 模式必要参数,code_verifier 校验码原文。

请求示例:

Authorization: 'Basic MTIzNDU2OjEyMzQ1Ng=='
https://demo.cloudentify.com/api/oauth/token?grant_type=authorization_code&redirect_
uri=http%3A%2F%2Fwww.baidu.com&code=123456&code_verifier=2D9RWc5iTdtejle7GTMzQ9Mg15InNmqk3GZL-Hg5Iz0&scope=openid

返回参数:

  • access_token:access_token令牌;
  • expires_in:access_token有效时间;
  • token_type:固定值“bearer”;
  • refresh_token:刷新令牌;
  • id_token:id_token。

返回示例:

{
  "access_token":"2YotnFZFEjr1zCsicMWpAA",
  "token_type":"bearer",
  "expires_in":3600,
  "refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA",
  "id_token":"eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJzdGV2ZW4iLCJBQ0NPVU5UIjoic3RldmVuIiwi
   aXNzIjoiaHR0cDpcL1wvd3d3LmJhaWR1LmNvbSIsImV4cCI6MTY1MDA5NTIzOX0.r7NCR3LF3ZoyhlX9UMERt6H_-DFCo6gcuTwsoTmI33U"
}

步骤3:

  • 访问令牌过期后,可使用刷新令牌置换新的访问令牌。
HTTP Method:POST
https://demo.cloudentify.com/api/oauth/token

请求参数:

  • Authorization:必填,存放Header中, 接口鉴权值,Basic base64encode(client_id:client_secret);
  • grant_type:必填,固定值“refresh_token”;
  • refresh_token:必填,refresh_token;
  • scope:必填,参数值应以 openid 开头。

请求示例:

Authorization: 'Basic MTIzNDU2OjEyMzQ1Ng=='
https://demo.cloudentify.com/api/oauth/token?grant_type=refresh_token&refresh_token=tGzv3JOkF0XG5Qx2TlKWIA&scope=openid

返回参数:

  • access_token:access_token令牌;
  • expires_in:access_token有效时间;
  • token_type:固定值“bearer”;
  • refresh_token:刷新令牌;
  • id_token:id_token。

返回示例:

{
   "access_token":"2YotnFZFEjr1zCsicMWpAA",
   "token_type":"bearer",
   "expires_in":3600,
   "refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA",     "id_token":"eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJzdGV2ZW4iLCJBQ0NPVU5UIjoic3RldmVuIiwiaXNzIjoiaHR0cDpcL1wvd3d3LmJhaWR1LmNvbSIsImV4cCI6MTY1MDA5NTIzOX0.r7NCR3LF3ZoyhlX9UMERt6H_-DFCo6gcuTwsoTmI33U"
}
  • 如果后台id_token 签名算法设置为RS256,可通过该接口获取算法信息和JWT 公钥对ID Token进行验证。
HTTP Method:GET
https://demo.cloudentify.com/api/oauth/oidc/{appkey}/.well-known/jwks.json

返回示例:

{
  "keys": [
    {
      "kid": "d98f49bc6ca4581eae8dfadd494fce10ea23aab0",
      "use": "sig",
      "kty": "RSA",
      "alg": "RS256",
      "e": "AQAB",
      "n":"tCwhHOxX_ylh5kVwfVqW7QIBTIsPjkjCjVCppDrynuF_3msEdtEaG64eJUz84ODFNMCC0BQ57G7wrKQVWkdSDxWUEqGk2BixBiHJRWZdof
      z1WOBTdPVicvHW5Zl_aIt7uXWMdOp_SODw-O2y2f05EqbFWFnR2-1y9K8KbiOp82CD72ny1Jbb_3PxTs2Z0F4ECAtTzpDteaJtjeeueRjr7040J
      AjQ-5fpL5D1g8x14LJyVIo-FL_y94NPFbMp7UCi69CIfVHXFO8WYFz949og-47mWRrID5lS4zpx-QLuvNhUb_lSqmylUdQB3HpRdOcYdj3xwy4M
      HJuu7tTaf0AmCQ"
    }
  ]
}

步骤4:

  • 应用可通过访问令牌获取用户信息。
HTTP Method:POST
https://demo.cloudentify.com/api/oauth/oidc/me?access_token=f148b9b4-2f02-42dd-8a59-4ca92a12c48b

返回示例:

{
   "sub": "steven",
   "name": "steven",
   "preferred_username": "steven",
   "given_name": "",
   "family_name": "",
   "middle_name": "",
   "nickname": "steven",
   "profile": "profile",
   "picture": "picture",
   "website": "",
   "gender": "U",
   "zoneinfo": "",
   "locale": "",
   "birthdate": "",
   "email": "",
   "email_verified": false,
   "phone_number": "",
   "phone_number_verified": false,
   "address": {
           "country": "",
           "region": "",
           "locality": "",
           "street_address": "",
           "formatted": "",
           "postal_code": ""
},
   "authorization": {
	   "roleList": [
		{
		   "roleCode": "OrderAdmin",
		   "descp": "订单管理员"
		},
            …
	     ],
	    "ruleList": [
		{
		    "accessmode": 0,
		    "accessmodeStr": "允许",
		    "resourceName": "订单管理",
		    "resourceCode": "1000",
		    "parentResourceCode": ""
		 },
            …
		]
	}
}

登录态注销(退出登录):

  • 业务系统主动调用飞天云信注销Access Token。
HTTP Method:POST
https://demo.cloudentify.com/api/oauth/oidc/endsession
Header Content-Type:application/x-www-form-urlencoded

FORM表单提交,请求参数:

id_token_hint:必填,填入id_token;

  • 业务系统被动等待飞天云信调用注销用户登录状态。

业务系统提供登出回调URL,接口描述如下:

HTTP Method:POST
Header Content-Type:application/x-www-form-urlencoded

接口参数:

  1. id:UUID;
  2. principal:登录业务系统的用户名;
  3. request:固定值“logoutRequest”;
  4. issueInstant:请求时间,格式为yyyy-MM-dd’T’HH:mm:ss.SSS’Z;
  5. online_ticket:id_token。