通过 IdentityServer 的身份验证后,IdentityManager 会发出这样的内部令牌。(请运行示例并检查请求 /api 或 api/Users 后发送的不记名令牌)
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 发出,因为外部 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() 方法我可以转到我的 IdentityServer 并要求进行身份验证,这非常好。如您所见,我可以获得我的 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 也不会接受我的授权。
当我删除 IdentityManager 项目中的安全性并在 api/Users 中放置一个断点时,我可以看到 Principal 有一些值,但它们都是空的。声明是空的,身份本身有一个对象但未经过身份验证。可能我在这段代码中遗漏了一些东西,它是我的 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 中进行身份验证,请告诉我如何操作。
提前致谢。丹尼尔