IdentityServer4元ユーザインタフェース情報のクエリの解析_5_

ディレクトリ

契約の分析

インタフェースにアクセスするには認証が必要なのUserInfoインターフェースはOAuth2.0を指定し、文はユーザーを認証するための情報を返すことがあります。UserInfoインターフェースは、利用要求トークンパスを必要とします。JSON応答パケットデータのフォーマットは、典型的には、セットを主張キーと値のペアのセットを含みます。必見の使用httpsで通信するためのUserInfoインターフェース。

RFC2616プロトコルによると、のUserInfoは、GETとPOSTメソッドをサポートしている必要があります。

UserInfoインターフェイスは、ベアラトークンを受け入れる必要があります。

UserInfoインターフェースは、JavaScriptクライアントのクロスドメインアクセスをサポートしなければならない、あなたはCORSプロトコルまたは他のプログラムを使用することができます。

UserInfo要求

GETメソッドは、のUserInfoインターフェーストークンベアラ要求ベアラAuthorizationヘッダを使用して推奨されます。

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

正常な応答

請求が空またはnullの場合、キーが返されません。
我々は、サブ(被写体)の文を返さなければなりません。
UserInfo一致id_tokenサブサブを返すことを確認する必要があり
、コンテンツタイプアプリケーション/ JSON、UTF-8でエンコードされている必要があり使用されなければならない
暗号化JWTリターンビット場合、コンテンツ型ビット必須アプリケーション/ JWT、

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": "[email protected]",
"picture": "http://example.com/janedoe/me.jpg"
}

失敗応答

HTTP/1.1 401 Unauthorized
WWW-Authenticate: error="invalid_token",
error_description="The Access Token expired"

応答確認で

クライアントは、次のことを確認する必要があります

  • チェック身元認証サービス(HTTPS)
  • 登録が終了すると、応答を受信したとき、対応する解読アルゴリズムと顧客がuserinfo_encrypted_response_alg設定されている場合
  • 応答が署名を持っている場合、クライアントは、テストに署名する必要があります

ソース決意

チェックアクセストークン

  • する最初の試みからAuthorizatonヘッド取得Bearer Token値を、言葉のリターンを見つけます
  • コンテンツタイプならば、の種類にフォームからフォームを取得しようとするaccess_tokenパラメータ値
  • 二つはに取得していないBeaer Tokenチェック失敗し、その結果が返されます
public async Task<BearerTokenUsageValidationResult> ValidateAsync(HttpContext context)
    {
        var result = ValidateAuthorizationHeader(context);
        if (result.TokenFound)
        {
            _logger.LogDebug("Bearer token found in header");
            return result;
        }

        if (context.Request.HasFormContentType)
        {
            result = await ValidatePostBodyAsync(context);
            if (result.TokenFound)
            {
                _logger.LogDebug("Bearer token found in body");
                return result;
            }
        }

        _logger.LogDebug("Bearer token not found");
        return new BearerTokenUsageValidationResult();
    }

検証リクエストパラメータ

IUserInfoRequestValidatorデフォルトの実装UserInfoRequestValidator参照チェックサムの。

  1. accessTokenあなたは含まなければならないopenid権利の声明を
  2. なければならないsub、と宣言subsubject一意に識別するために、ユーザーの略頭字語
  3. 収集accessTokenすべてclaim、次のユーザー情報を削除することは無関係ですclaim
    at_hash、AUD、AZP、c_hash、 CLIENT_ID、EXP、IAT、ISS、JTI、ナンス、NBF、reference_token_id、SID、スコープ
    スクリーニング後claimの名前を作成UserInfoPrincipal
  4. コール返し、その後、起動状態、ユーザーが有効になっているかどうかを判断する方法ではなく、エラーをIProfileServiceIsAcriveAsyncinvalid_token
  5. 構築の工程を含む、成功したチェック結果のオブジェクトを返します3Principal

public async Task<UserInfoRequestValidationResult> ValidateRequestAsync(string accessToken)
{
    // the access token needs to be valid and have at least the openid scope
    var tokenResult = await _tokenValidator.ValidateAccessTokenAsync(
        accessToken,
        IdentityServerConstants.StandardScopes.OpenId);

    if (tokenResult.IsError)
    {
        return new UserInfoRequestValidationResult
        {
            IsError = true,
            Error = tokenResult.Error
        };
    }

    // the token must have a one sub claim
    var subClaim = tokenResult.Claims.SingleOrDefault(c => c.Type == JwtClaimTypes.Subject);
    if (subClaim == null)
    {
        _logger.LogError("Token contains no sub claim");

        return new UserInfoRequestValidationResult
        {
            IsError = true,
            Error = OidcConstants.ProtectedResourceErrors.InvalidToken
        };
    }

    // create subject from incoming access token
    var claims = tokenResult.Claims.Where(x => !Constants.Filters.ProtocolClaimsFilter.Contains(x.Type));
    var subject = Principal.Create("UserInfo", claims.ToArray());

    // make sure user is still active
    var isActiveContext = new IsActiveContext(subject, tokenResult.Client, IdentityServerConstants.ProfileIsActiveCallers.UserInfoRequestValidation);
    await _profile.IsActiveAsync(isActiveContext);

    if (isActiveContext.IsActive == false)
    {
        _logger.LogError("User is not active: {sub}", subject.GetSubjectId());

        return new UserInfoRequestValidationResult
        {
            IsError = true,
            Error = OidcConstants.ProtectedResourceErrors.InvalidToken
        };
    }

    return new UserInfoRequestValidationResult
    {
        IsError = false,
        TokenValidationResult = tokenResult,
        Subject = subject
    };
}

応答メッセージを生成します

コールIUserInfoResponseGeneratorのインタフェースのデフォルトの実装応答メッセージを生成する方法を。UserInfoResponseGeneratorProcessAsync

  1. 結果から得られたチェックscope宣言された値は、クエリscopeの関連する値IdentityResourceすべて(リソースの同一性)とその関連しますclaimその結果、すべてのユーザーの要求ということですclaim
  2. 呼び出すメソッドを、チェック結果を返すユーザ要求の交差点を。DefaultProfileServiceGetProfileDataAsyncclaimclaim
  3. もしclaimセットでないsubチェック結果取って、sub値を。場合はIProfileService、戻りsubチェック結果の値を持つ文でsub値が矛盾してスロー例外です。
  4. 戻りclaimコレクションを。
  5. 書き込みヘッドに対応してCache-Control:no-store, no-cache, max-age=0Pragma:no-cache
  6. claim書き込み応答フォーマットJSONとコンテンツのセット
 public virtual async Task<Dictionary<string, object>> ProcessAsync(UserInfoRequestValidationResult validationResult)
{
    Logger.LogDebug("Creating userinfo response");

    // extract scopes and turn into requested claim types
    var scopes = validationResult.TokenValidationResult.Claims.Where(c => c.Type == JwtClaimTypes.Scope).Select(c => c.Value);
    var requestedClaimTypes = await GetRequestedClaimTypesAsync(scopes);

    Logger.LogDebug("Requested claim types: {claimTypes}", requestedClaimTypes.ToSpaceSeparatedString());

    // call profile service
    var context = new ProfileDataRequestContext(
        validationResult.Subject,
        validationResult.TokenValidationResult.Client,
        IdentityServerConstants.ProfileDataCallers.UserInfoEndpoint,
        requestedClaimTypes);
    context.RequestedResources = await GetRequestedResourcesAsync(scopes);

    await Profile.GetProfileDataAsync(context);
    var profileClaims = context.IssuedClaims;

    // construct outgoing claims
    var outgoingClaims = new List<Claim>();

    if (profileClaims == null)
    {
        Logger.LogInformation("Profile service returned no claims (null)");
    }
    else
    {
        outgoingClaims.AddRange(profileClaims);
        Logger.LogInformation("Profile service returned the following claim types: {types}", profileClaims.Select(c => c.Type).ToSpaceSeparatedString());
    }

    var subClaim = outgoingClaims.SingleOrDefault(x => x.Type == JwtClaimTypes.Subject);
    if (subClaim == null)
    {
        outgoingClaims.Add(new Claim(JwtClaimTypes.Subject, validationResult.Subject.GetSubjectId()));
    }
    else if (subClaim.Value != validationResult.Subject.GetSubjectId())
    {
        Logger.LogError("Profile service returned incorrect subject value: {sub}", subClaim);
        throw new InvalidOperationException("Profile service returned incorrect subject value");
    }

    return outgoingClaims.ToClaimsDictionary();
}

おすすめ

転載: www.cnblogs.com/holdengong/p/12594007.html