用于 OAuth 客户机授权的 JSON Web 令牌 (JWT)

用于 OAuth 客户机授权的 JWT 允许客户机在交换中将已签名 JWT 令牌发送至 OpenID Connect 提供者以获取 OAuth 2.0 访问令牌。

用于 OAuth 客户机授权的 JWT 包含在 openidConnectServer-1.0 功能部件中。它允许客户机在交换中将已签名 JWT 令牌发送至 OpenID Connect 提供者以获取 OAuth 2.0 访问令牌。

以下是此功能的可能示例使用方案:电子公司的客户授权每月自动从网上银行自动付款。假定电子公司和网上银行已就满足这类请求方面建立信任关系。电子公司可将带有相应声明的已签名 JWT 令牌发送至 OpenID Connect 提供者的令牌端点 URI,这些声明是针对网上银行配置的,用于每月请求 OAuth 2.0 访问令牌。然后电子公司可使用该访问令牌每月通过网上银行付款。

配置为 OpenID Connect 提供者的 Liberty 服务器支持 用于 OAuth 2.0 客户机认证和授权的 JSON Web 令牌 (JWT) 概要文件规范的某些部分。想要支持 JWT 客户机功能的用户必须使用他们自己的应用程序完成此操作。

授权范围

OpenID Connect 客户机将带有 JWT 的 HTTPS 请求发送至 OpenID Connect 提供者的令牌端点以请求访问令牌。在此过程中,用户不会见到任何有关针对使用范围授权的同意表单。JWT 处理程序将根据以下条件处理授权范围:

  1. 如果未在请求中指定任何范围参数,那么 OpenID Connect 提供者不会在访问令牌中指定任何范围。
  2. 如果 OpenID Connect 客户机在 OpenID Connect 提供程序配置中被限定为 autoAuthorized 客户机,那么该客户机在请求中指定的任何范围是在访问令牌的范围列表中指定的。
  3. 如果 OpenID Connect 客户机未被限定为 autoAuthorized 客户机,那么请求中包含的范围需要被客户机配置中的范围列表过滤,并且也必须在 preAuthorizedScope 列表中指定。如果 HTTPS 请求中的范围在客户机配置的 scopepreAuthorizeScope 列表中,那么可在访问令牌的范围列表中指定该范围。

如果客户机未被限定为 autoAuthorized 客户机,那么必须在客户机配置中正确配置可包含在访问令牌的范围列表中的范围。该范围必须包含在 OpenID Connect 提供者的客户机配置的 scopepreAuthorizedScope 属性值中。在所显示的示例中,范围 profileemail 是在访问令牌的范围列表中指定的,因为这两个范围都包含在 scopepreAuthorizedScope 值列表中。如果某个范围未列示在客户机配置的 scope 属性中,那么系统会在访问令牌的范围列表中省略该范围。如果某个范围列示在 scope 属性中但未包含在客户机配置的 preAuthorizedScope 列表中,那么授权请求会在 OpenID Connect 提供者返回的响应中触发 invalid_grant 错误。

<openidConnectProvider id="OidcConfigSample" oauthProviderRef="OAuthConfigSample" />
<oauthProvider id="OAuthConfigSample" ... >
        ...
        <localStore>
            <client name="client01" secret="{xor}..."
                    displayname="client01"
                    scope="profile email phone"
                    preAuthorizedScope="profile email"
                    enabled="true" />
            ...
        </localStore>
    </oauthProvider>

JSON Web 令牌中的声明

必须签署有效 JSON Web 令牌。 配置为 OpenID Connect 提供者的 Liberty 服务器仅支持 HMAC-SHA256 作为令牌签名算法。每个 OpenID Connect 客户机的签名密钥是 OpenID Connect 提供者的客户机配置中的 secret 属性。在所显示的示例中,所使用的签名密钥将为 "{xor}LDo8LTor"

<client name="client01" displayname="client01" secret="{xor}LDo8LTor" ... />

OpenID Connect 提供者也会验证 JWT 中的以下声明:

'iss' (issuer)
此声明在 JWT 中是必需的。iss 声明必须与 OpenID Connect 提供者中的客户机配置的 name 属性或 redirect 属性相匹配。在以下示例中,iss 声明必须与 client01http://op201406.ibm.com:8010/oauthclient/redirect.jsp 匹配。
<client name="client01" redirect="http://op201406.ibm.com:8010/oauthclient/redirect.jsp" scope="openid profile email" ... />
'sub' (subject)
此声明在 JWT 中是必需的。主体集的值必须是 OpenID Connect 提供者服务器的用户注册表中的有效用户名。
'aud' (audience)
此声明在 JWT 中是必需的。如果在 openidConnectProvider 配置中指定了 issuerIdentifier 属性,那么受众声明的值为 issuerIdentifier 的名称。如果未在 openidConnectProvider 配置中指定 issuerIdentifier 属性,那么受众必须是 OpenID Connect 提供者的令牌端点 URI。在以下示例中,受众声明的值将为 "OpenIDConnectProviderID1"
<openidConnectProvider id="OidcConfigSample" oauthProviderRef="OAuthConfigSample" issuerIdentifier="OpenIDConnectProviderID1" />
'exp' (expiration)
此声明在 JWT 中是必需的,并且限制可使用 JWT 的时间范围。OpenID Connect 提供者针对其系统时钟验证 exp,附加允许的一些时钟偏差。
'nbf' (not before)
这是可选声明。如果此声明存在,那么此令牌仅在此声明指定的时间后有效。OpenID Connect 提供者针对其系统时钟验证此时间,附加允许的一些时钟偏差。
'iat' (issued at)
缺省情况下,这是可选声明。但是,如果 jwtGrantType 元素的 iatRequired 属性设置为 true,那么所有 JWT 必须包含 iat 声明。如果 iat 声明存在,那么该声明指示发出 JWT 的时间。发出 JWT 的时长不能超过 maxTokenLifetime
'jti' (JWT ID)
这是可选声明,它是 JWT 令牌的唯一标识。如果 JWT 标识存在,那么发出者不能复用同一 JWT 标识。例如,如果 client01 发出 jtiid6098364921 的 JWT,那么 client01 发出的所有其他 JWT 的 jti 值都不能为 id6098364921jti 声明与另一 JWT 完全相同的 JWT 被视为重放攻击。配置为 OpenID Connect 提供者的 Liberty 服务器在服务器上设置 jti 高速缓存。高速缓存的大小由 jwtGrantType 配置中的 maxJtiCacheSize 指定。系统会针对任何新进入的 jti 标识检查保留在高速缓存中的 jti 标识。存储在高速缓存中的 jti 标识不会被废弃,除非高速缓存已满。

提交 JSON Web 令牌请求

最好使用 HTTPS 协议而不是 HTTP 来提交 JWT 请求。OpenID Connect 提供者的令牌端点用于处理 HTTPS JWT 请求。要确定 OpenID Connect 提供者的令牌端点,请参阅调用 OpenID Connect 的令牌端点OAuth 端点 URL

该请求必须包含以下参数:

  • grant_type - 此参数的值必须为 "urn:ietf:params:oauth:grant-type:jwt-bearer"
  • assertion - 此参数的值必须包含单个已签名 JWT 令牌。
  • scope - 此参数是可选的。如果省略了 scope,那么返回的访问令牌不会包含任何范围。系统会针对 OpenID Connect 提供者配置检查 scope 参数中列示的范围值。有关更多信息,请参阅先前的“授权范围”部分。
  • client_id - 此参数的值必须与 OpenID Connect 提供者的客户机配置中的 name 属性匹配。
  • client_secret - 此参数的值必须与 OpenID Connect 提供者的客户机配置中的 secret 属性匹配。

示例 HTTPS 请求:

POST /token.oauth2 HTTP/1.1
    Host: oidc.ibm.com
    Content-Type: application/x-www-form-utlencoded

    client_id=client01
    &client_secret=secret     
    &grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer     
    &assertion=eyJhbGc[---omitted---]kIn0.eyJpc[---ommitted---]A4fQ.MB6ZFlCsHg5MJ-weIHZYz6xgF1jdSZn7ErchHs8-8Rk     
    &scope=profile email

用于创建已签名 JWT 令牌的 Java 示例:

package com.ibm.sample;

import java.security.SignatureException;
import com.google.gson.JsonObject;
import net.oauth.jsontoken.crypto.HmacSHA256Signer;

import net.oauth.jsontoken.SystemClock;
import net.oauth.jsontoken.JsonToken;
import org.joda.time.Duration;
import org.joda.time.Instant;

public class SampleJWTToken {
        private static final Duration SKEW = Duration.standardMinutes(5);

        JsonToken jwtToken = null;
        String[] allPayloadKeys = { "iss", "sub", "aud", "exp", // required
                                    "nbf", "iat", "jti" }; // optional

        public SampleJWTToken(String clientId, 
                              String keyId,
                              String signKey,
                              String audience, 
                              String subject, // user
                              String jtiId) throws Exception { // InvalidKeyException

                byte[] hs256Key = signKey.getBytes();
                HmacSHA256Signer hmacSha256Signer = new HmacSHA256Signer(
                                clientId, keyId, hs256Key);
                // _rsaSha256Signer = new RsaSHA256Signer(clientId, _keyId,
                //                                        _privateKey);
                SystemClock clock = new SystemClock(SKEW);
                jwtToken = new JsonToken(hmacSha256Signer, clock);
                JsonObject headerObj = jwtToken.getHeader();
                JsonObject payloadObj = jwtToken.getPayloadAsJsonObject();

                headerObj.addProperty("alg", "HS256");

                Instant instantExp = clock.now().plus(600000); // 10 minutes
                jwtToken.setExpiration(instantExp);
                jwtToken.setAudience(audience);
                payloadObj.addProperty("iss", clientId);
                payloadObj.addProperty("sub", subject);

                // optional
                payloadObj.addProperty("jti", jtiId);
                jwtToken.setIssuedAt(clock.now()); // issued at time
        }

        public String getJWTTokenString() throws Exception {
                String signedAndSerializedString = null;
                try {          
                        signedAndSerializedString = jwtToken.serializeAndSign();
                } catch (SignatureException e) {
                        throw e;
                }
                return signedAndSerializedString;
        }
}

用于指示主题类型的图标 概念主题



时间戳记图标 最近一次更新时间: Tuesday, 6 December 2016
http://www14.software.ibm.com/webapp/wsbroker/redirect?version=cord&product=was-nd-mp&topic=cwlp_jwttoken
文件名:cwlp_jwttoken.html