如何将声明包含在从授权端点检索到的访问令牌中?

时间:2016-06-15 17:24:18

标签: c# .net oauth-2.0 identityserver3

我想在通过IdSrv进行身份验证时检索的访问令牌中默认包含声明。声明Ticket应始终包含在访问令牌中,因此我创建了一个作为资源范围的新范围,并将Ticket包含为ScopeClaim。但是,当IdSrv创建访问令牌并调用GetProfileDataAsync时,您可以从IdSrv日志中看到,上下文中请求的声明列表为空,因此不会向访问令牌添加任何声明。

默认情况下,如何将此声明包含在访问令牌中?

我的印象是,请求Resource范围会允许范围中的声明作为访问令牌的一部分返回。

作用域

        public static List<Scope> Get()
        {
            return new List<Scope>
            {
                StandardScopes.OpenId //standard scope when dealing with open id connect
                ,
                StandardScopes.OfflineAccess
                ,
                new Scope
                {
                    Name = "App",
                    DisplayName = "App",
                    Type = ScopeType.Identity,
                    Claims = new List<ScopeClaim>
                    {
                        new ScopeClaim
                        {
                            AlwaysIncludeInIdToken = false,
                            Name = "App",
                            Description = "Role Information"
                        },
//                        new ScopeClaim
//                        {
//                            AlwaysIncludeInIdToken = false,
//                            Name = "Ticket",
//                            Description = "Login ticket"
//                        }
                    },
                    IncludeAllClaimsForUser = false
                },
                new Scope
                {
                    Name = "AppAccess",
                    DisplayName = "AppAccess",
                    Type = ScopeType.Resource,
                    Claims = new List<ScopeClaim>
                    {
                        new ScopeClaim
                        {
                            Name = "Ticket",
                            Description = "Login ticket",
                        }
                    },
                    IncludeAllClaimsForUser = true
                }
            };

权利要求

    public static List<Client> Get()
    {
        return new List<Client>
        {
            new Client
            {
                ClientName = "Hybrid Flow",
                ClientId = "apphybrid",
                Enabled = true,
                Flow = Flows.Hybrid,
                AllowAccessToAllScopes = true,
                IdentityTokenLifetime = 120,
                AccessTokenLifetime = 400,
                RequireConsent = false,
                ClientSecrets = new List<Secret>
                {
                    new Secret("secret".Sha256())
                },
                RedirectUris = new List<string>
                {
                    "localhost/App/login/Login.mr"
                },
                PostLogoutRedirectUris = new List<string>
                {
                    "localhost/App/login/Login.mr"
                },
                AllowedScopes = new List<string>
                {
                    Constants.StandardScopes.OpenId,
                    Constants.StandardScopes.OfflineAccess,
                    "App",
                    "AppAccess"
                }
            }
        };
    }

IDSrv配置

public override Task AuthenticateLocalAsync(LocalAuthenticationContext context)
        {
            var securityServiceProxy = new SecurityServiceProxy(new ServiceHeadersParameters { UserHostAddress = Ctx.Request.Host.Value });

            var ticket = securityServiceProxy.UseServiceClient(serviceClient => serviceClient.AuthenticateUser(context.UserName, context.Password, Configuration.ProviderCode));

            if (!ticket.IsValid())
            {
                context.AuthenticateResult = new AuthenticateResult("Invalid credentials");
                return Task.FromResult(0);
            }

            var claims = new List<Claim> {
                new Claim(GlobalConstant.TicketClaim, ticket.Ticket.ToString())
            };

            context.AuthenticateResult = new AuthenticateResult(
                ticket.UserObjId.ToString(),
                context.UserName,
                claims: claims,
                authenticationMethod: Constants.AuthenticationMethods.Password,
                identityProvider: Configuration.ProviderCode
                );

            return Task.FromResult(0);
        }

        public override Task GetProfileDataAsync(ProfileDataRequestContext context)
        {
            var applicationDto = GetApplicationDto(context);

            var claims = new List<Claim>
            {
                new Claim(Constants.ClaimTypes.Subject, context.Subject.GetSubjectId()),
            };

            Log.Debug("The requested claims...");
            if (context.RequestedClaimTypes == null)
            {
                Log.Debug("Requested Claims is null");
            }
            else
            {
                foreach (var x in context.RequestedClaimTypes)
                {
                    Log.Debug($"Claims {x}");
                }

                if (context.RequestedClaimTypes.Contains(GlobalConstant.TicketClaim))
                    claims.Add(context.Subject.Claims.Where(x => x.Type.Equals(GlobalConstant.TicketClaim)).FirstOrDefault());

                if (context.RequestedClaimTypes.Contains(GlobalConstant.ApplicationClaim))
                    claims.Add(new Claim(GlobalConstant.ApplicationClaim, applicationDto.Jsonify()));
            }

            // set the issued claims - these are the ones that were requested, if available
            context.IssuedClaims = claims;
            Log.Debug("Finished ProfileDataAsync");
            return Task.FromResult(0);
        }

        private ApplicationDto GetApplicationDto(ProfileDataRequestContext context)
        {
            var securityServiceProxy = new SecurityServiceProxy(new ServiceHeadersParameters { UserHostAddress = Ctx.Request.Host.Value });

            return securityServiceProxy.UseServiceClient(serviceClient => serviceClient.RetrieveAuthenticatedUser(GetUserTicketFromContext(context)));
        }

        private static UserTicketDto GetUserTicketFromContext(ProfileDataRequestContext context)
        {
            Log.Debug("The claims in the context...");
            foreach(var x in context.Subject.Claims)
            {
                Log.Debug($"Cliams {x.Type} {x.Value}");
            }

            var ticketString = context.Subject.Claims.Where(x => x.Type.Equals(GlobalConstant.TicketClaim)).FirstOrDefault()?.Value;
            var userIdString = context.Subject.GetSubjectId();

            Guid Ticket, UserId;

            if(Guid.TryParse(ticketString, out Ticket) && Guid.TryParse(userIdString, out UserId))
            {
                return new UserTicketDto { Ticket = Ticket, UserObjId = UserId };
            }

            return new UserTicketDto();
        }

网络配置

    JwtSecurityTokenHandler.InboundClaimTypeMap = new Dictionary<string, string>();

    AntiForgeryConfig.UniqueClaimTypeIdentifier = IdentityModel.JwtClaimTypes.Name;

    app.Use(async (ctx, next) => { await next(); });

    app.UseCookieAuthentication(new CookieAuthenticationOptions
    {
        AuthenticationType = "cookies"
    });

    app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions
    {
        ClientId = OAuthConstant.Client,
        RedirectUri = "localhost/App/login/Login.mr",
        PostLogoutRedirectUri = "localhost/App/login/Login.mr",
        Authority = "localhost/Oauth2server/securetoken",
        SignInAsAuthenticationType = "Cookies",
        ResponseType = "token code id_token",
        Scope = "OpenId App offline_access AppAccess",
        ClientSecret = "secret",
        UseTokenLifetime = false,
        Notifications = new OpenIdConnectAuthenticationNotifications()
        {
            AuthorizationCodeReceived = IdentityServerClient.HandleOther,
            SecurityTokenReceived = IdentityServerClient.HandleOther,
            MessageReceived = IdentityServerClient.HandleOther,
            AuthenticationFailed = IdentityServerClient.HandleOther,
            RedirectToIdentityProvider = IdentityServerClient.HandleRedirectToIdentityProvider,
            SecurityTokenValidated = IdentityServerClient.HandleSecurityTokenValidated
        }
    });

日志

2016-06-15 12:04:51.943 -05:00 [Information] Login page submitted
2016-06-15 12:04:55.320 -05:00 [Information] Login credentials successfully validated by user service
2016-06-15 12:04:55.332 -05:00 [Information] Calling PostAuthenticateAsync on the user service
2016-06-15 12:04:55.338 -05:00 [Information] issuing primary signin cookie
2016-06-15 12:04:55.344 -05:00 [Information] redirecting to: http://localhost/OAuth2Server/securetoken/connect/authorize?client_id=apphybrid&redirect_uri=http:%2F%2Flocalhost%2Fapp%2FLogin%2FLogin.mr&response_mode=form_post&response_type=code id_token token&scope=App openid offline_access AppAccess&state=OpenIdConnect.AuthenticationProperties%3DebxFcJnjMiMq2m1gPqBsYlrBWdLct2kaJSYn-s0nxImnff-37i4t8Wa3wAJewJGFe9msgeeqJDKtR1gwwfA0e8Pdd6RNAi6YPo_CqT4l5zV8ifohYQVN9TrWfLXITXuKId9IW2cCeRQL6d8uWfkzSANqAGSbSGJYZ5pgOLULQresbAiJ7N77FgBmgrVtX4hDQuwGGL5vZFCb_C5tjl8_ezH12w8zQfifKuLwjaDmOSGYyo2AqpowQXXeSSSDgKBF&nonce=636016067018002117.MWY4MGVjOWItYTFjYS00MTVlLTg4MDYtMjYxYjkwMWEzNzU4ZWViNzEyNTQtMjE0Mi00MjYzLTk2ZjMtODdhYmIxYTM5Mjg5
2016-06-15 12:04:55.368 -05:00 [Debug] Incoming request: /securetoken/connect/authorize
2016-06-15 12:04:55.381 -05:00 [Information] Start authorize request
2016-06-15 12:04:55.381 -05:00 [Information] Start authorize request protocol validation
2016-06-15 12:04:55.381 -05:00 [Information] "Authorize request validation success"
 "{
  \"ClientId\": \"apphybrid\",
  \"ClientName\": \"app Hybrid Flow\",
  \"RedirectUri\": \"http://localhost/app/Login/Login.mr\",
  \"AllowedRedirectUris\": [
    \"http://localhost/app/Login/Login.mr\"
  ],
  \"SubjectId\": \"783bf872-b864-4042-853d-04fbcb7a505a\",
  \"ResponseType\": \"code id_token token\",
  \"ResponseMode\": \"form_post\",
  \"Flow\": \"Hybrid\",
  \"RequestedScopes\": \"app openid offline_access appAccess\",
  \"State\": \"OpenIdConnect.AuthenticationProperties=ebxFcJnjMiMq2m1gPqBsYlrBWdLct2kaJSYn-s0nxImnff-37i4t8Wa3wAJewJGFe9msgeeqJDKtR1gwwfA0e8Pdd6RNAi6YPo_CqT4l5zV8ifohYQVN9TrWfLXITXuKId9IW2cCeRQL6d8uWfkzSANqAGSbSGJYZ5pgOLULQresbAiJ7N77FgBmgrVtX4hDQuwGGL5vZFCb_C5tjl8_ezH12w8zQfifKuLwjaDmOSGYyo2AqpowQXXeSSSDgKBF\",
  \"Nonce\": \"636016067018002117.MWY4MGVjOWItYTFjYS00MTVlLTg4MDYtMjYxYjkwMWEzNzU4ZWViNzEyNTQtMjE0Mi00MjYzLTk2ZjMtODdhYmIxYTM5Mjg5\",
  \"SessionId\": \"e79cd97a339b4513b45038e7755c1b88\",
  \"Raw\": {
    \"client_id\": \"apphybrid\",
    \"redirect_uri\": \"http://localhost/app/Login/Login.mr\",
    \"response_mode\": \"form_post\",
    \"response_type\": \"code id_token token\",
    \"scope\": \"app openid offline_access appAccess\",
    \"state\": \"OpenIdConnect.AuthenticationProperties=ebxFcJnjMiMq2m1gPqBsYlrBWdLct2kaJSYn-s0nxImnff-37i4t8Wa3wAJewJGFe9msgeeqJDKtR1gwwfA0e8Pdd6RNAi6YPo_CqT4l5zV8ifohYQVN9TrWfLXITXuKId9IW2cCeRQL6d8uWfkzSANqAGSbSGJYZ5pgOLULQresbAiJ7N77FgBmgrVtX4hDQuwGGL5vZFCb_C5tjl8_ezH12w8zQfifKuLwjaDmOSGYyo2AqpowQXXeSSSDgKBF\",
    \"nonce\": \"636016067018002117.MWY4MGVjOWItYTFjYS00MTVlLTg4MDYtMjYxYjkwMWEzNzU4ZWViNzEyNTQtMjE0Mi00MjYzLTk2ZjMtODdhYmIxYTM5Mjg5\"
  }
}"
2016-06-15 12:04:55.399 -05:00 [Information] Creating Hybrid Flow response.
2016-06-15 12:04:55.412 -05:00 [Information] Creating Implicit Flow response.
2016-06-15 12:04:55.416 -05:00 [Debug] Creating access token
2016-06-15 12:04:55.424 -05:00 [Debug] Getting ProfileDataAsync
2016-06-15 12:04:55.436 -05:00 [Debug] The claims in the context...
2016-06-15 12:04:55.437 -05:00 [Debug] Cliams sub 783bf872-b864-4042-853d-04fbcb7a505a
2016-06-15 12:04:55.437 -05:00 [Debug] Cliams name dev.guser
2016-06-15 12:04:55.437 -05:00 [Debug] Cliams amr password
2016-06-15 12:04:55.437 -05:00 [Debug] Cliams idp IDSRV
2016-06-15 12:04:55.437 -05:00 [Debug] Cliams auth_time 1466010295
2016-06-15 12:04:55.437 -05:00 [Debug] Cliams ticket fc05cd84-7756-4ec5-ac3c-53ac6d4d5e2a
2016-06-15 12:04:55.975 -05:00 [Debug] The requseted claims...
2016-06-15 12:04:55.976 -05:00 [Debug] Requested Claims Is Null
2016-06-15 12:04:55.976 -05:00 [Debug] Finished ProfileDataAsync
2016-06-15 12:04:55.982 -05:00 [Debug] Creating JWT access token
2016-06-15 12:04:56.049 -05:00 [Debug] Creating identity token
2016-06-15 12:04:56.054 -05:00 [Information] Getting claims for identity token for subject: 783bf872-b864-4042-853d-04fbcb7a505a
2016-06-15 12:04:56.054 -05:00 [Debug] Getting ProfileDataAsync
2016-06-15 12:04:56.066 -05:00 [Debug] The claims in the context...
2016-06-15 12:04:56.066 -05:00 [Debug] Cliams sub 783bf872-b864-4042-853d-04fbcb7a505a
2016-06-15 12:04:56.066 -05:00 [Debug] Cliams name dev.guser
2016-06-15 12:04:56.066 -05:00 [Debug] Cliams amr password
2016-06-15 12:04:56.066 -05:00 [Debug] Cliams idp IDSRV
2016-06-15 12:04:56.066 -05:00 [Debug] Cliams auth_time 1466010295
2016-06-15 12:04:56.066 -05:00 [Debug] Cliams ticket fc05cd84-7756-4ec5-ac3c-53ac6d4d5e2a
2016-06-15 12:04:56.338 -05:00 [Debug] The requseted claims...
2016-06-15 12:04:56.338 -05:00 [Debug] Cliams sub
2016-06-15 12:04:56.338 -05:00 [Debug] Finished ProfileDataAsync
2016-06-15 12:04:56.338 -05:00 [Debug] Creating JWT identity token
2016-06-15 12:04:56.344 -05:00 [Debug] Adding client "apphybrid" to client list cookie for subject "783bf872-b864-4042-853d-04fbcb7a505a"
2016-06-15 12:04:56.349 -05:00 [Information] End authorize request
2016-06-15 12:04:56.352 -05:00 [Information] Posting to http://localhost/app/Login/Login.mr
2016-06-15 12:04:56.352 -05:00 [Debug] Using AssetManager to render authorization response HTML
2016-06-15 12:04:56.388 -05:00 [Debug] Incoming request: /securetoken/assets/app.FormPostResponse.js

//Web 
2016-06-15 12:04:56,422 [16] DEBUG app.Web.IdentityServer.IdentityServerClient Triggered MessageReceivedNotification`2 notification
2016-06-15 12:04:56,426 [16] DEBUG app.Web.IdentityServer.IdentityServerClient Triggered SecurityTokenReceivedNotification`2 notification
2016-06-15 12:04:56,487 [16] DEBUG app.Web.IdentityServer.IdentityServerClient Triggered SecurityTokenValidated notification
2016-06-15 12:04:56,487 [16] DEBUG app.Web.IdentityServer.IdentityServerClient The Claims in the identity
2016-06-15 12:04:56,488 [16] DEBUG app.Web.IdentityServer.IdentityServerClient Claims: iss http://localhost/OAuth2Server/securetoken
2016-06-15 12:04:56,488 [16] DEBUG app.Web.IdentityServer.IdentityServerClient Claims: aud apphybrid
2016-06-15 12:04:56,488 [16] DEBUG app.Web.IdentityServer.IdentityServerClient Claims: exp 1466010416
2016-06-15 12:04:56,488 [16] DEBUG app.Web.IdentityServer.IdentityServerClient Claims: nbf 1466010296
2016-06-15 12:04:56,488 [16] DEBUG app.Web.IdentityServer.IdentityServerClient Claims: nonce 636016067018002117.MWY4MGVjOWItYTFjYS00MTVlLTg4MDYtMjYxYjkwMWEzNzU4ZWViNzEyNTQtMjE0Mi00MjYzLTk2ZjMtODdhYmIxYTM5Mjg5
2016-06-15 12:04:56,488 [16] DEBUG app.Web.IdentityServer.IdentityServerClient Claims: iat 1466010296
2016-06-15 12:04:56,488 [16] DEBUG app.Web.IdentityServer.IdentityServerClient Claims: at_hash 6pIu3P1cEeTQJMcK8Gcnhw
2016-06-15 12:04:56,488 [16] DEBUG app.Web.IdentityServer.IdentityServerClient Claims: c_hash VsSw9HC0xyodlSkSCZefLw
2016-06-15 12:04:56,488 [16] DEBUG app.Web.IdentityServer.IdentityServerClient Claims: sid e79cd97a339b4513b45038e7755c1b88
2016-06-15 12:04:56,488 [16] DEBUG app.Web.IdentityServer.IdentityServerClient Claims: sub 783bf872-b864-4042-853d-04fbcb7a505a
2016-06-15 12:04:56,488 [16] DEBUG app.Web.IdentityServer.IdentityServerClient Claims: auth_time 1466010295
2016-06-15 12:04:56,488 [16] DEBUG app.Web.IdentityServer.IdentityServerClient Claims: idp IDSRV
2016-06-15 12:04:56,488 [16] DEBUG app.Web.IdentityServer.IdentityServerClient Claims: amr password
2016-06-15 12:04:56,488 [16] DEBUG app.Web.IdentityServer.IdentityServerClient The access token: [Omitted]
2016-06-15 12:04:56,488 [16] DEBUG app.Web.IdentityServer.IdentityServerClient The id token: [Omitted]
2016-06-15 12:04:56,491 [16] DEBUG app.Web.IdentityServer.IdentityServerClient Triggered AuthenticationFailedNotification`2 notification
//Web

//Logs

有问题的日志输出......

2016-06-15 12:04:55.412 -05:00 [Information] Creating Implicit Flow response.
2016-06-15 12:04:55.416 -05:00 [Debug] Creating access token
2016-06-15 12:04:55.424 -05:00 [Debug] Getting ProfileDataAsync
2016-06-15 12:04:55.436 -05:00 [Debug] The claims in the context...
2016-06-15 12:04:55.437 -05:00 [Debug] Cliams sub 783bf872-b864-4042-853d-04fbcb7a505a
2016-06-15 12:04:55.437 -05:00 [Debug] Cliams name dev.guser
2016-06-15 12:04:55.437 -05:00 [Debug] Cliams amr password
2016-06-15 12:04:55.437 -05:00 [Debug] Cliams idp IDSRV
2016-06-15 12:04:55.437 -05:00 [Debug] Cliams auth_time 1466010295
2016-06-15 12:04:55.437 -05:00 [Debug] Cliams ticket fc05cd84-7756-4ec5-ac3c-53ac6d4d5e2a    <- Has the claim I want
2016-06-15 12:04:55.975 -05:00 [Debug] The requseted claims...
2016-06-15 12:04:55.976 -05:00 [Debug] Requested Claims Is Null    <- but this needs to indicate that we want that claim...
2016-06-15 12:04:55.976 -05:00 [Debug] Finished ProfileDataAsync

1 个答案:

答案 0 :(得分:1)

更新2:现在好了,我看得更近了,你有IncludeAllClaimsForUser = true。在GetProfileData中,上下文中有一个可比较的标志。我怀疑这就是为什么你没有在集合中提出任何要求。

更新1:您希望加入代币的声明应添加到GetProfile中,而不是AuthenticateResult方法中的AuthentivcateLocal

原文:将范围类型从Identity更改为Resource。这会影响索赔所涉及的令牌。