如何在单点登录项目中向Identity Server 4传递应用名称
在IdentityServer4中传递Application Name的几种实用方案
嘿,我来帮你搞定这个问题!在IdentityServer4(IS4)里传递你的application-name其实有几种贴合不同场景的方式,我给你拆解清楚:
1. 单应用对应独立Client:用ClientName配置
如果你的每个业务应用都在IS4中注册了单独的Client,那最简单的方式就是直接在Client配置里设置ClientName字段——IS4会自动把这个名称和对应的授权请求关联起来。
IS4端配置示例
在你的IS4配置类(比如Config.cs)里,给目标Client添加ClientName:
public static IEnumerable<Client> GetClients() { return new List<Client> { new Client { ClientId = "your-app-client-id", ClientName = "你的Application Name", // 这里就是要传递的应用名称 AllowedGrantTypes = GrantTypes.Code, RedirectUris = { "https://your-app.com/signin-oidc" }, PostLogoutRedirectUris = { "https://your-app.com/signout-callback-oidc" }, AllowedScopes = { "openid", "profile", "api1" }, // 其他必要配置... } }; }
在IS4中获取这个名称
在登录页面、授权逻辑里,你可以通过客户端存储获取当前请求对应的Client信息:
// 注入IClientStore private readonly IClientStore _clientStore; private readonly IIdentityServerInteractionService _interaction; public async Task<IActionResult> Login(string returnUrl) { var authContext = await _interaction.GetAuthorizationContextAsync(returnUrl); if (authContext != null) { var client = await _clientStore.FindClientByIdAsync(authContext.ClientId); var appName = client.ClientName; // 拿到你的应用名称 // 可以把appName传递给视图,比如显示在登录页面标题上 ViewBag.AppName = appName; } // 其他登录逻辑... }
2. 多应用共用一个Client:通过自定义请求参数传递
如果多个业务应用共用同一个IS4 ClientId,那你可以在发起授权请求时,手动添加application-name作为自定义参数。
应用端发起请求时添加参数
不管你用的是OIDC客户端库(比如ASP.NET Core的OpenID Connect中间件)还是手动构造URL,都可以加上这个参数:
- 手动构造URL示例:
https://your-is4-server/connect/authorize? client_id=shared-client-id &redirect_uri=https://your-app.com/callback &response_type=code &scope=openid profile &application-name=你的应用名称 // 自定义参数 - ASP.NET Core中间件配置示例:
services.AddAuthentication(options => { options.DefaultScheme = "Cookies"; options.DefaultChallengeScheme = "oidc"; }) .AddCookie("Cookies") .AddOpenIdConnect("oidc", options => { options.Authority = "https://your-is4-server"; options.ClientId = "shared-client-id"; options.ResponseType = "code"; // 自定义授权请求参数 options.Events = new OpenIdConnectEvents { OnRedirectToIdentityProvider = context => { context.ProtocolMessage.SetParameter("application-name", "你的应用名称"); return Task.CompletedTask; } }; // 其他配置... });
在IS4中获取自定义参数
在IS4的授权逻辑里,你可以从授权上下文的请求参数中提取这个值:
public async Task<IActionResult> Login(string returnUrl) { var authContext = await _interaction.GetAuthorizationContextAsync(returnUrl); if (authContext != null) { // 从请求Query中获取自定义参数 var appName = authContext.Request.Query["application-name"].FirstOrDefault(); // 如果需要在整个流程中保留这个值,可以存入上下文Properties authContext.Properties.Items["application-name"] = appName; } // 其他逻辑... }
3. 把Application Name加入Token:通过ProfileService添加自定义Claim
如果希望用户登录后,application-name作为Claim出现在ID Token或Access Token中,供业务应用直接使用,那可以通过自定义IProfileService实现。
实现自定义ProfileService
public class CustomProfileService : IProfileService { private readonly UserManager<ApplicationUser> _userManager; private readonly IIdentityServerInteractionService _interaction; private readonly IClientStore _clientStore; private readonly IHttpContextAccessor _httpContextAccessor; public CustomProfileService(UserManager<ApplicationUser> userManager, IIdentityServerInteractionService interaction, IClientStore clientStore, IHttpContextAccessor httpContextAccessor) { _userManager = userManager; _interaction = interaction; _clientStore = clientStore; _httpContextAccessor = httpContextAccessor; } public async Task GetProfileDataAsync(ProfileDataRequestContext context) { var sub = context.Subject.GetSubjectId(); var user = await _userManager.FindByIdAsync(sub); if (user == null) { throw new ArgumentException("用户不存在"); } var claims = new List<Claim> { new Claim(ClaimTypes.Name, user.UserName), new Claim(ClaimTypes.Email, user.Email) }; // 获取application-name并添加为Claim var returnUrl = _httpContextAccessor.HttpContext.Request.Query["returnUrl"].FirstOrDefault(); var authContext = await _interaction.GetAuthorizationContextAsync(returnUrl); var appName = authContext?.Request.Query["application-name"].FirstOrDefault() ?? (await _clientStore.FindClientByIdAsync(authContext.ClientId)).ClientName; claims.Add(new Claim("application-name", appName)); context.IssuedClaims = claims; } public async Task IsActiveAsync(IsActiveContext context) { var sub = context.Subject.GetSubjectId(); var user = await _userManager.FindByIdAsync(sub); context.IsActive = user != null; } }
注册ProfileService到IS4
在Startup.cs的ConfigureServices里添加:
services.AddIdentityServer() .AddProfileService<CustomProfileService>() // 其他IS4配置(AddInMemoryClients、AddInMemoryIdentityResources等)...
这样,业务应用在获取Token后,就能从Claims中直接取出application-name了。
内容的提问来源于stack exchange,提问作者A.J
相关产品推荐
相关产品推荐

