首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在另一个域中使用IdentityManager与IdentityServer的身份验证

在另一个域中使用IdentityManager与IdentityServer的身份验证
EN

Stack Overflow用户
提问于 2017-09-13 18:28:52
回答 2查看 745关注 0票数 0

在通过IdentityServer进行身份验证之后,IdentityManager发出如下所示的内部令牌。(请运行例句并检查请求/api或api/用户后发送的承载令牌)

代码语言:javascript
复制
authorization:Bearer UQgpIqqyn_lgUukES3PqHFEuf0_2sz26Jsh848K_4DYdiYeQLkSazg43MT2BdWSC-EY--iUYAPKk4rD9-8sq0_nbf2Z7XDzPlcDL0LdAP8oNyKUDCOLeap9zCEaB4ve1VE1Q_e5JGYsx_jTvs-yYlUI5fMn-6OBxunlNcTwPq-xv6hOXZhh-PUGIE9Ndhkptd0zt5r1A3UAvvTk72yI6yD40yRnl1KhNEQw33UNVMIeV4vWqwiXHtyoxi87e3r4_x3IyzZeEqxtwPIPH1l6o1s7HfZozspaTbaq9gPLvuaXa0dQjf5lA2CIGs5z8Fa3W

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

使用HostSecurityConfiguration或LocalSecurityConfiguration对我不起作用,因为他们在内部使用OAuthAuthorizationServerProvider,提供者发出一个令牌(上面的那个),它对最终IdentityManager将在内部调用的API无效。保存的令牌必须由我自己的IdentityServer发出,因为外部IdentityServer正在等待它的令牌。

我试过使用ExternalBearerTokenConfiguration,但没有成功。每次我尝试使用这个类做一些事情时,我都被重定向到令牌%20令牌,而且这个url显然不存在,因为权限从https://localhost:44337/ids开始,而ExternalBearerTokenConfiguration假设我的提供者位于相同的域中。

这是ExternalBearerTokenConfiguration的配置

代码语言:javascript
复制
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上的方法IdentityManager.Assets.EmbeddedHtmlResult()--我可以转到我的IdentityServer --并请求身份验证,这真的很好。如您所见,我可以获得我的id_token和访问令牌中的所有内容。这个方法的好处在于,内部保存的令牌是我从我的IdentityServer中获得的。

代码语言:javascript
复制
{
    "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会验证我的令牌,所以我得到了授权,我确信这一点,因为我可以在=> =>下面的代码中看到这一行中的所有内容。问题是UseIdentityManager不接受我的授权,即使UseIdentityServerBearerTokenAuthentication已经这样做了。

当我删除IdentityManager项目中的安全性并放置一个断点(例如在api/Users中)时,我可以看到主体有一些值,但它们都是空的。声明是空的,标识本身有一个对象,但没有经过身份验证。可能我在这段代码中遗漏了一些东西,那就是我的UseIdentityServerBearerTokenAuthentication身份验证和UseIdentityManager之间的胶水。

代码语言:javascript
复制
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();
    });
});

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

提前谢谢。丹尼尔

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2017-09-16 15:56:52

我找到了解决办法。

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

代码语言:javascript
复制
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中像这样使用它

代码语言:javascript
复制
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位中使用。

现在,Bearer令牌如下所示:

代码语言:javascript
复制
authorization:Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6ImEzck1VZ01Gdjl0UGNsTGE2eUYzekFrZnF1RSIsImtpZCI6ImEzck1VZ01Gdjl0UGNsTGE2eUYzekFrZnF1RSJ9.eyJjbGllbnRfaWQiOiJpZG1ncl9jbGllbnQiLCJzY29wZSI6WyJvcGVuaWQiLCJpZG1nciIsIk15QXBpIl0sInN1YiI6Ijk1MWE5NjVmLTFmODQtNDM2MC05MGU0LTNmNmRlYWM3YjliYyIsImFtciI6WyJwYXNzd29yZCJdLCJhdXRoX3RpbWUiOjE1MDU1NzYzNTAsImlkcCI6Imlkc3J2IiwibmFtZSI6IkFkbWluIiwicm9sZSI6IklkZW50aXR5TWFuYWdlckFkbWluaXN0cmF0b3IiLCJpc3MiOiJodHRwczovL2xvY2FsaG9zdDo0NDMzOC9pZHMiLCJhdWQiOiJodHRwczovL2xvY2FsaG9zdDo0NDMzOC9pZHMvcmVzb3VyY2VzIiwiZXhwIjoxNTA1NTgwMzU4LCJuYmYiOjE1MDU1NzY3NTh9.iVsEuswGDdMGo-x-NdPxMEln6or9e7p8G-8iSK746_Wapcwi_-N7EcY3G8GKj0YvExO4i605kfNjsTDAd14zQvT6UyU8_gcGO84DhQRM_MWpirfhlPWu6flXT4dRzYberjgHhDEOzROsrHofVAAZD_51BEE1FgAQrqCCWar2POSi9AsLFJ_AxFRnMlbZbZy8adJiMGOUFhtBXzhJVYzuolAMJ08NBTzmaK5vLsEn9Ok-09ZGX3MOpq2aBfES1hRJKEP-LDhMNo4dQn0mQ9Y-gGvkpXMmZQ6tC8yUs2PokJ5eGsFqevK6zpvJDiKPPjoN01QJtEqZ2UU_oGzMEKwyUA

我用代码创建了一个github存储库

票数 0
EN

Stack Overflow用户

发布于 2017-09-13 22:56:53

IdentityManager回购有使用IdentityServer3作为IdentityManager的Idp的一个例子

同时,还可以找到一些相关的讨论,如在这个线程中

编辑:

我还没有像您所描述的那样研究IdentityManager在内部对令牌做什么。但是,对于外部API调用,您不能也请求一个访问令牌(而不是只请求id_token),然后保存该访问令牌并使用它对外部API进行调用吗?这将是Identity Server发出的令牌,默认情况下它将是JWT。

下面是示例中的代码将如何更改;请查看标记为“--编辑--.”的两个注释下面的代码

本质上,我只是请求和访问令牌,然后保存它.

代码语言:javascript
复制
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
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/46204520

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档