如何将IdentityServer4身份映射到任何WebApp(.Net MVC样板,.Net核心样板) [英] How to map IdentityServer4 Identity to any WebApp (.Net MVC Boilerplate, .Net Core Boilerplate)
问题描述
我正在创建一个SSO服务器,以将所有用户集中在ActiveDirectory(AD)中,并在那里管理它们,而不是每个特定应用程序的数据库.
I'm creating an SSO server, to centralize all users in ActiveDirectory(AD) and manage them there instead of the database of each specific application.
要制造此服务器,我将IdentityServer4(Idsr4)与 Ldap/AD扩展
To made this server I used IdentityServer4(Idsr4) with Ldap/AD Extension
我已将Idsr4设置为使用基于AD的身份(这是集中身份"),并且用户现在可以使用自己的AD登录名/密码登录Idsr4
I've setted the Idsr4 to use identity based on AD (this is "centralized identity"), and users now can login on Idsr4 with own AD login/ password
现在的问题是如何将集中式身份映射到应用程序.我想在多个应用程序中使用同一身份用户.
The question now is how to map the centralized identity to applications. I want to use same identity user in several applications.
我通读了IdentityServer4的文档,但找不到与所建议的结构相关的任何内容.
I read through the documentation of IdentityServer4 but could not find anything related to a proposed structure.
有人有清晰的结构设置可用于了解整个设置吗? (如Asp.Net MVC Boilerplate,IdentityServer4,受保护的Api之类的分隔.)
Does anybody have a clear structure setup which could be used to understand the whole setup? (Separation like Asp.Net MVC Boilerplate, IdentityServer4, Protected Api.)
IdentityServer4配置:
IdentityServer4 Config:
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
// configure identity server with in-memory stores, keys, clients and scopes
services.AddIdentityServer()
.AddDeveloperSigningCredential()
////.AddSigningCredential(...) // Strongly recommended, if you want something more secure than developer signing (Read The Manual since it's highly recommended)
.AddInMemoryIdentityResources(InMemoryInitConfig.GetIdentityResources())
.AddInMemoryApiResources(InMemoryInitConfig.GetApiResources())
.AddInMemoryClients(InMemoryInitConfig.GetClients())
.AddLdapUsers<OpenLdapAppUser>(Configuration.GetSection("IdentityServerLdap"), UserStore.InMemory);
}
IdentityServer4 InMemoryInitConfig:
IdentityServer4 InMemoryInitConfig:
namespace QuickstartIdentityServer{
public class InMemoryInitConfig
{
// scopes define the resources in your system
public static IEnumerable<IdentityResource> GetIdentityResources()
{
return new List<IdentityResource>
{
new IdentityResources.OpenId(),
new IdentityResources.Profile(),
};
}
public static IEnumerable<ApiResource> GetApiResources()
{
return new List<ApiResource>
{
new ApiResource("api1", "My API")
};
}
// clients want to access resources (aka scopes)
public static IEnumerable<Client> GetClients()
{
// client credentials client
return new List<Client>
{
//DEMO HTTP CLIENT
new Client
{
ClientId = "demo",
ClientSecrets = new List<Secret> {new Secret("password".Sha256()) } ,
ClientName = "demo",
AllowedGrantTypes = {
GrantType.ClientCredentials, // Server to server
GrantType.ResourceOwnerPassword, // User to server
GrantType.Implicit
},
//GrantTypes.HybridAndClientCredentials,
AllowAccessTokensViaBrowser = true,
AllowOfflineAccess = true,
AccessTokenLifetime = 90, // 1.5 minutes
AbsoluteRefreshTokenLifetime = 0,
RefreshTokenUsage = TokenUsage.OneTimeOnly,
RefreshTokenExpiration = TokenExpiration.Sliding,
UpdateAccessTokenClaimsOnRefresh = true,
RequireConsent = false,
RedirectUris = {
"http://localhost:6234/"
},
PostLogoutRedirectUris = { "http://localhost:6234" },
AllowedCorsOrigins ={ "http://localhost:6234/" },
AllowedScopes =
{
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Profile,
"api1"
},
},
};
}
}
}
我的客户端配置:
public void Configuration(IAppBuilder app)
{
app.UseAbp();
app.UseOAuthBearerAuthentication(AccountController.OAuthBearerOptions);
// ABP
//app.UseCookieAuthentication(new CookieAuthenticationOptions
//{
// AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
// LoginPath = new PathString("/Account/Login"),
// // evaluate for Persistent cookies (IsPermanent == true). Defaults to 14 days when not set.
// //ExpireTimeSpan = new TimeSpan(int.Parse(ConfigurationManager.AppSettings["AuthSession.ExpireTimeInDays.WhenPersistent"] ?? "14"), 0, 0, 0),
// //SlidingExpiration = bool.Parse(ConfigurationManager.AppSettings["AuthSession.SlidingExpirationEnabled"] ?? bool.FalseString)
// ExpireTimeSpan = TimeSpan.FromHours(12),
// SlidingExpiration = true
//});
// END ABP
/// IDENTITYSERVER
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = "Cookies"
});
app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions
{
Authority = "http://localhost:5443", //ID Server
ClientId = "demo",
ClientSecret = "password",
ResponseType = "id_token token",
SignInAsAuthenticationType = "Cookies",
RedirectUri = "http://localhost:6234/", //URL of website when cancel login on idsvr4
PostLogoutRedirectUri = "http://localhost:6234", //URL Logout ??? << when this occor
Scope = "openid",
RequireHttpsMetadata = false,
//AuthenticationMode = Microsoft.Owin.Security.AuthenticationMode.Active,
});
/// END IDENTITYSERVER
app.UseExternalSignInCookie("Cookies");
app.MapSignalR();
}
更新
我正在阅读有关OpenID Connect的文档,发现可以为httpContext创建通知,以便在Idsrv4 userinfo端点中接受用户的声明,如下所示:
UPDATE
I was reading the documentation on OpenID Connect and saw that it is possible to create notifications for httpContext to take the user's claims in the Idsrv4 userinfo endpoint like this:
public void Configuration(IAppBuilder app)
{
app.UseAbp();
// ABP
//app.UseOAuthBearerAuthentication(AccountController.OAuthBearerOptions);
//app.UseCookieAuthentication(new CookieAuthenticationOptions
//{
// AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
// LoginPath = new PathString("/Account/Login"),
// // evaluate for Persistent cookies (IsPermanent == true). Defaults to 14 days when not set.
// //ExpireTimeSpan = new TimeSpan(int.Parse(ConfigurationManager.AppSettings["AuthSession.ExpireTimeInDays.WhenPersistent"] ?? "14"), 0, 0, 0),
// //SlidingExpiration = bool.Parse(ConfigurationManager.AppSettings["AuthSession.SlidingExpirationEnabled"] ?? bool.FalseString)
// ExpireTimeSpan = TimeSpan.FromHours(12),
// SlidingExpiration = true
//});
// END ABP
/// IDENTITYSERVER
AntiForgeryConfig.UniqueClaimTypeIdentifier = Thinktecture.IdentityModel.Client.JwtClaimTypes.Subject;
JwtSecurityTokenHandler.DefaultInboundClaimFilter.Clear();
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = "Cookies"
});
// CONFIG OPENID
var openIdConfig = new OpenIdConnectAuthenticationOptions
{
Authority = "http://localhost:5443", //ID Server
ClientId = "demo",
ClientSecret = "password",
ResponseType = "id_token token",
SignInAsAuthenticationType = "Cookies",
RedirectUri = "http://localhost:6234/", //URL of website when cancel login on idsvr4
PostLogoutRedirectUri = "http://localhost:6234", //URL Logout ??? << when this occor
Scope = "openid profile api1",
RequireHttpsMetadata = false,
// get userinfo
Notifications = new OpenIdConnectAuthenticationNotifications {
SecurityTokenValidated = async n => {
var userInfoClient = new UserInfoClient(
new Uri(n.Options.Authority + "/connect/userinfo"),
n.ProtocolMessage.AccessToken);
var userInfo = await userInfoClient.GetAsync();
// create new identity and set name and role claim type
var nid = new ClaimsIdentity(
n.AuthenticationTicket.Identity.AuthenticationType,
ClaimTypes.GivenName,
ClaimTypes.Role);
foreach (var x in userInfo.Claims) {
nid.AddClaim(new Claim(x.Item1, x.Item2));
}
// keep the id_token for logout
nid.AddClaim(new Claim("id_token", n.ProtocolMessage.IdToken));
// add access token for sample API
nid.AddClaim(new Claim("access_token", n.ProtocolMessage.AccessToken));
// keep track of access token expiration
nid.AddClaim(new Claim("expires_at", DateTimeOffset.Now.AddSeconds(int.Parse(n.ProtocolMessage.ExpiresIn)).ToString()));
// add some other app specific claim
//nid.AddClaim(new Claim("app_specific", "some data"));
n.AuthenticationTicket = new AuthenticationTicket(
nid,
n.AuthenticationTicket.Properties);
n.Request.Headers.SetValues("Authorization ", new string[] { "Bearer ", n.ProtocolMessage.AccessToken });
}
}
};
// END CONFIG OPENID
app.UseOpenIdConnectAuthentication(openIdConfig);
/// END IDENTITYSERVER
app.UseExternalSignInCookie("Cookies");
app.MapSignalR();
}
更新2
谢谢@Khanh TO,
UPDATE 2
Thank you @Khanh TO,
我按照您的建议做了,我保留了每个应用程序的数据库
I did exactly what you recommended, I kept the database of each application
但是,我不再通过应用程序数据库来管理用户,我对从idsr4 userinfo端点获取的方法进行了硬编码
However to no longer manage the users by the application database, I hardcode a method that takes from the idsr4 userinfo endpoint
在abpUsers表中创建或更新用户所需的信息,然后应用程序解释数据并采取必要的操作
The information needed to create or update a user in the abpUsers table, then the application interprets the data and does the necessary actions
更具体地说:
在我发送给客户端AccountController
的redirect_uri
中,我有一个ActionResult
可以完成所有这些工作,调用在客户端userstable上创建/更新用户的必要方法
More specifically:
In the redirect_uri
I send to the AccountController
of my client, there I have an ActionResult
that does all this work calling the necessary methods to create/update an user on client userstable
推荐答案
我认为GrantType.ResourceOwnerPassword
流不支持AD
登录,也不被UseOpenIdConnectAuthentication
都不支持,您可以使用Implicit
或Hybrid
流.
在对客户端mvc应用进行身份验证后,您可以在HttpContext.User
中查看任何声明,并以用户身份找到正确的声明值(它们只是声明,而无需创建本地帐户)
I think the GrantType.ResourceOwnerPassword
flow doens't support AD
login and not support by the UseOpenIdConnectAuthentication
neither , you can use Implicit
or Hybrid
flow.
Once you authenticate the to your client mvc app, you can view any claims in HttpContext.User
and find the correct claim value as user's identity (they are just claims , and no need to create a local account)
这篇关于如何将IdentityServer4身份映射到任何WebApp(.Net MVC样板,.Net核心样板)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!