在另一个域中使用身份服务器身份验证IdentityManager

问题描述:

在IdentityServer进行身份验证后,IdentityManager会发出一个像这样的内部令牌。 (请运行the example和检查请求/ API或API后发送的承载令牌/用户)在另一个域中使用身份服务器身份验证IdentityManager

authorization:Bearer UQgpIqqyn_lgUukES3PqHFEuf0_2sz26Jsh848K_4DYdiYeQLkSazg43MT2BdWSC-EY--iUYAPKk4rD9-8sq0_nbf2Z7XDzPlcDL0LdAP8oNyKUDCOLeap9zCEaB4ve1VE1Q_e5JGYsx_jTvs-yYlUI5fMn-6OBxunlNcTwPq-xv6hOXZhh-PUGIE9Ndhkptd0zt5r1A3UAvvTk72yI6yD40yRnl1KhNEQw33UNVMIeV4vWqwiXHtyoxi87e3r4_x3IyzZeEqxtwPIPH1l6o1s7HfZozspaTbaq9gPLvuaXa0dQjf5lA2CIGs5z8Fa3W 

我确实需要IdentityManager保存在登录过程中我自己IdentityServer颁发的JWT,并使用该令牌调用api而不是使用上面那种令牌。为什么?因为我想从IdentityManager本身调用一个外部API,该API期望由我自己的IdentityServer服务器发出一个令牌。

使用HostSecurityConfiguration或LocalSecurityConfiguration不适用于我,因为它们在内部使用OAuthAuthorizationServerProvider,并且该提供程序发出一个Token(上面那个),它对IdentityManager内部将调用的API无效。令牌保存MUST由我自己的IdentityServer颁发,因为外部API正期待它的令牌。

我尝试使用ExternalBearerTokenConfiguration而没有成功。每次我尝试使用此类时,我都被重定向到 https://localhost:44337/idm/connect/authorize?state=8030030589322682&nonce=7778993666881238&client_id=idmgr&response_type=id_token%20token ,并且该URL显然不存在,因为该权限以https://localhost:44337/ids开头,ExternalBearerTokenConfiguration假定我的提供程序位于同一个域中。

这是ExternalBearerTokenConfiguration

idm.UseIdentityManager(new IdentityManagerOptions 
      { 
       Factory = factory, 
       SecurityConfiguration = new ExternalBearerTokenConfiguration() 
       { 
        RequireSsl = false, 
        SigningCert = Cert.Load(), 
        Issuer = "https://localhost:44337/ids", 
        Scope = "idmgr", 
        Audience = $"https://localhost:44337/ids/resources", 
        BearerAuthenticationType = "Cookies" 
       } 
      }); 

在另一个方向去配置,我发现,在IdentityManager.Assets.EmbeddedHtmlResult修改方法GetResponseMessage()我可以去我Ide​​ntityServer和我要求的验证,从而真的很好。如你所见,我可以得到我的id_token和访问令牌。好的思考这种方法是,内部保存的令牌是我从IdentityServer获得的令牌。

{ 
    "client_id": "idmgr_client", 
    "scope": [ 
    "openid", 
    "idmgr", 
    "WebUserAccountsApi" 
    ], 
    "sub": "951a965f-1f84-4360-90e4-3f6deac7b9bc", 
    "amr": [ 
    "password" 
    ], 
    "auth_time": 1505323819, 
    "idp": "idsrv", 
    "name": "Admin", 
    "role": "IdentityManagerAdministrator", 
    "iss": "https://localhost:44336/ids", 
    "aud": "https://localhost:44336/ids/resources", 
    "exp": 1505327419, 
    "nbf": 1505323819 
} 

所以,现在我已经得到了几乎所有我需要什么,什么时候发IdentityServer我回到我的/ IDM端点(这是IdentityManager端点)UseIdentityServerBearerTokenAuthentication验证我的令牌,所以我得到了认可,我相信的因为我可以在下面的代码中看到这一行中的所有内容=> context.Authentication.User.Identity.IsAuthenticated。问题是即使UseIdentityServerBearerTokenAuthentication已经做到了,UseIdentityManager也不会接受我的授权。

当我删除I​​dentityManager项目中的安全性,并在api/Users中放置了一个断点时,我可以看到委托人有一些值,但所有值都是空的。声明是空的,身份本身有一个对象,但未经过身份验证。可能我在这段代码中缺少一些东西,这是我的UseIdentityServerBearerTokenAuthentication认证和UseIdentityManager之间的粘连。

app.Map("/idm", idm => 
{ 
    var factory = new IdentityManagerServiceFactory(); 

    var rand = new System.Random(); 
    var users = Users.Get(rand.Next(5000, 20000)); 
    var roles = Roles.Get(rand.Next(15)); 

    factory.Register(new Registration<ICollection<InMemoryUser>>(users)); 
    factory.Register(new Registration<ICollection<InMemoryRole>>(roles)); 
    factory.IdentityManagerService = new Registration<IIdentityManagerService, InMemoryIdentityManagerService>(); 

    idm.Use(async (context, next) => 
    { 
     await next.Invoke(); 
    }); 
    JwtSecurityTokenHandler.InboundClaimTypeMap = new Dictionary<string, string>(); 

    idm.UseIdentityServerBearerTokenAuthentication(new IdentityServerBearerTokenAuthenticationOptions 
    { 
     Authority = Constants.authority, 
     RequiredScopes = new[] { "idmgr" } 
    }); 

    idm.Use(async (context, next) => 
    { 
     if (context.Authentication.User != null && 
       context.Authentication.User.Identity != null && 
       context.Authentication.User.Identity.IsAuthenticated) 
     { 
      /*var xxx = ""; 
     } 
     await next.Invoke(); 
    }); 


    idm.UseIdentityManager(new IdentityManagerOptions 
    { 
     Factory = factory 
    }); 

    idm.Use(async (context, next) => 
    { 
     await next.Invoke(); 
    }); 
}); 

如果你知道我缺少什么,请评论。所有的想法都受到欢迎。 如果您知道如何使用您自己的IdentityServer在IdentityManager中进行身份验证,请告诉我如何执行此操作。

在此先感谢。 Daniel

我发现:请参阅代码标记的两点意见下这是一个解决方案。

我创建了一个名为OAuthSettings的类,另一个名为EmptySecurityConfiguration。我使用它们是这样的:

idm.UseIdentityManager(new IdentityManagerOptions 
      { 
       Factory = factory, 
       SecurityConfiguration = new EmptySecurityConfiguration 
       { 
        OAuthSettings = new OAuthSettings() 
        { 
         authorization_endpoint = authority + "/connect/authorize", 
         client_id = "idmgr_client", 
         authority = authority, 
         response_type = "id_token token", 
         redirect_uri = idmUrl + "/#/callback/", 
         //scope = "openid", 
         scope = "openid idmgr MyApi", 
         //response_mode = "" 
         acr_values = "tenant:anything", 
         load_user_profile = true 
        } 
       } 
      }); 

我不得不修改SecurityConfiguration类来添加我的OAuthSettings属性。

然后我使用它像这样EmbeddedHtmlResult

OAuthSettings OAuthSettings = null; 
     if (this.securityConfiguration.OAuthSettings == null) 
     { 
      OAuthSettings = new OAuthSettings 
      { 
       authorization_endpoint = this.authorization_endpoint, 
       client_id = Constants.IdMgrClientId 
      }; 
     } 
     else 
     { 
      OAuthSettings = this.securityConfiguration.OAuthSettings; 
     } 

     var html = AssetManager.LoadResourceString(this.file, 
      new { 
       pathBase = this.path, 
       model = Newtonsoft.Json.JsonConvert.SerializeObject(new 
       { 
        PathBase = this.path, 
        ShowLoginButton = this.securityConfiguration.ShowLoginButton, 
        oauthSettings = OAuthSettings 
       }) 
      }); 

之后,你必须运行代码,仅此而已。您已获得由IdentityServer颁发的令牌并将其保存以便在JavaScript位中使用。

现在承载令牌是这样的:

authorization:Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6ImEzck1VZ01Gdjl0UGNsTGE2eUYzekFrZnF1RSIsImtpZCI6ImEzck1VZ01Gdjl0UGNsTGE2eUYzekFrZnF1RSJ9.eyJjbGllbnRfaWQiOiJpZG1ncl9jbGllbnQiLCJzY29wZSI6WyJvcGVuaWQiLCJpZG1nciIsIk15QXBpIl0sInN1YiI6Ijk1MWE5NjVmLTFmODQtNDM2MC05MGU0LTNmNmRlYWM3YjliYyIsImFtciI6WyJwYXNzd29yZCJdLCJhdXRoX3RpbWUiOjE1MDU1NzYzNTAsImlkcCI6Imlkc3J2IiwibmFtZSI6IkFkbWluIiwicm9sZSI6IklkZW50aXR5TWFuYWdlckFkbWluaXN0cmF0b3IiLCJpc3MiOiJodHRwczovL2xvY2FsaG9zdDo0NDMzOC9pZHMiLCJhdWQiOiJodHRwczovL2xvY2FsaG9zdDo0NDMzOC9pZHMvcmVzb3VyY2VzIiwiZXhwIjoxNTA1NTgwMzU4LCJuYmYiOjE1MDU1NzY3NTh9.iVsEuswGDdMGo-x-NdPxMEln6or9e7p8G-8iSK746_Wapcwi_-N7EcY3G8GKj0YvExO4i605kfNjsTDAd14zQvT6UyU8_gcGO84DhQRM_MWpirfhlPWu6flXT4dRzYberjgHhDEOzROsrHofVAAZD_51BEE1FgAQrqCCWar2POSi9AsLFJ_AxFRnMlbZbZy8adJiMGOUFhtBXzhJVYzuolAMJ08NBTzmaK5vLsEn9Ok-09ZGX3MOpq2aBfES1hRJKEP-LDhMNo4dQn0mQ9Y-gGvkpXMmZQ6tC8yUs2PokJ5eGsFqevK6zpvJDiKPPjoN01QJtEqZ2UU_oGzMEKwyUA 

我创建与code

IdentityManager回购有an example使用IdentityServer3作为IdentityManager的Idp。

一些相关的讨论可以发现in this thread,以及...

编辑:

我没有研究过什么IdentityManager在内部与令牌做像你描述。但是,对于外部API调用,您是否也可以请求访问令牌(而不是只有一个id_token),然后保存该访问令牌并使用它来调用外部API?这将是由Identity Server颁发的令牌,默认情况下它将是JWT。

下面是示例代码的改变方式;本质“ - 编辑...”

,我只是请求和访问令牌,然后将其保存....

app.UseOpenIdConnectAuthentication(new Microsoft.Owin.Security.OpenIdConnect.OpenIdConnectAuthenticationOptions 
{ 
    AuthenticationType = "oidc", 
    Authority = "https://localhost:44337/ids", 
    ClientId = "idmgr_client", 
    RedirectUri = "https://localhost:44337", 

    // ---EDIT--- request id_token AND access_token 
    ResponseType = "id_token token", 

    UseTokenLifetime = false, 
    Scope = "openid idmgr", 
    SignInAsAuthenticationType = "Cookies", 
    Notifications = new Microsoft.Owin.Security.OpenIdConnect.OpenIdConnectAuthenticationNotifications 
    { 
     SecurityTokenValidated = n => 
     { 
      n.AuthenticationTicket.Identity.AddClaim(new Claim("id_token", n.ProtocolMessage.IdToken)); 

      // --EDIT-- save access_token 
      n.AuthenticationTicket.Identity.AddClaim(new Claim("access_token", n.ProtocolMessage.AccessToken)); 

      return Task.FromResult(0); 
     }, 
     RedirectToIdentityProvider = async n => 
     { 
      if (n.ProtocolMessage.RequestType == Microsoft.IdentityModel.Protocols.OpenIdConnectRequestType.LogoutRequest) 
      { 
       var result = await n.OwinContext.Authentication.AuthenticateAsync("Cookies"); 
       if (result != null) 
       { 
        var id_token = result.Identity.Claims.GetValue("id_token"); 
        if (id_token != null) 
        { 
         n.ProtocolMessage.IdTokenHint = id_token; 
         n.ProtocolMessage.PostLogoutRedirectUri = "https://localhost:44337/idm"; 
        } 
       } 
      } 
     } 
    } 
}); 
+0

喜罗布一个GitHub的仓库,谢谢你的评论,但实际上是例如不与我要求的要求工作以上。在这个例子中,内部令牌不是一个IdentityServer令牌。确实,登录是通过IdentityServer完成的,但不幸的是,IdentityServer令牌没有保存,而是他们发布了一个内部令牌来保护Api(甚至不是JWT令牌)。运行示例并检查它在访问Api时发送的承载令牌。你会看到我在说什么。 –

+0

Rob,这是IdentityServer进行身份验证后在内部使用的令牌。正如你所看到的,他们不救JWT通过IdentityServer在登录过程中发出的令牌,而是他们发出另一个标记,这是这一个:授权:承载UQgpIqqyn_lgUukES3PqHFEuf0_2sz26Jsh848K_4DYdiYeQLkSazg43MT2BdWSC-EY - iUYAPKk4rD9-8sq0_nbf2Z7XDzPlcDL0LdAP8oNyKUDCOLeap9zCEaB4ve1VE1Q_e5JGYsx_jTvs-yYlUI5fMn-6OBxunlNcTwPq-xv6hOXZhh-PUGIE9Ndhkptd0zt5r1A3UAvvTk72yI6yD40yRnl1KhNEQw33UNVMIeV4vWqwiXHtyoxi87e3r4_x3IyzZeEqxtwPIPH1l6o1s7HfZozspaTbaq9gPLvuaXa0dQjf5lA2CIGs5z8Fa3W –

+0

@DanielBoteroCorrea--我在上面更新了我的答案。 –