我在使用应用程序(Blazor 服务器/WASM)对 IS4 服务器上的用户进行身份验证时遇到问题。 我的 IDSRV4 与要保护的 API 位于同一应用程序上,每个客户端都有自己的数据库(用于用户和业务模型)。
为了选择好的数据库,我使用了标头,并在 EF Core 上设置了一个拦截器来根据标头值选择数据库。
除了身份验证之外,一切都很好。我正在使用 resource_owner_password 流与 JavaScript 应用程序(安全漏洞,我知道),这允许我为每个调用传递自定义标头(使用我的自定义标头调用 /connect/token)。
现在,通过 authorization_code 流程,我无法设法传递标头来选择好的租户,这意味着好的数据库,这会导致身份验证失败,因为令牌是在用户当前注册的另一个数据库上进行验证的。
我可以在登录过程中通过租户选择数据库(在 IDSRV4 端发布登录信息时),并且我已经在客户端设置了事件,以便在发送回代码以返回 id_token 时添加标头,但我失去了该功能在我的 idp 重定向用户登录 /connect/authorize 后执行此操作(IDSRV4 端似乎没有用于添加自定义标头的扩展)。
因此,我的用户发布了登录数据(带有租户信息),这些数据在重定向到 /connect/authorize 时丢失了,而且我无法对此进行自定义。有机会这样做吗?
将所有用户合并到同一个数据库中不是一个选项。
您仍然可以将任何自定义标头添加到托管 Identityserver 的 MVC 应用程序中的任何
HttpResponse
。
// public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
app.UseCustomHeaders();
//CustomHeadersMiddleware.cs
public static class CustomHeadersMiddlewareExtensions
{
public static IApplicationBuilder UseCustomHeaders(
this IApplicationBuilder builder)
{
return builder.UseMiddleware<CustomHeadersMiddleware>();
}
}
public class CustomHeadersMiddleware
{
private readonly RequestDelegate _next;
private readonly ILogger<CustomHeadersMiddleware> _logger;
public CustomHeadersMiddleware(RequestDelegate next,
ILogger<CustomHeadersMiddleware> logger)
{
_next = next;
_logger = logger;
}
public async Task Invoke(HttpContext context)
{
var watch = new Stopwatch();
watch.Start();
//To add Headers AFTER everything you need to do this
context.Response.OnStarting(() =>
{
if (!context.Response.Headers.ContainsKey("X-Response-Time-Milliseconds"))
context.Response.Headers.Add("X-Response-Time-Milliseconds",
new[] {watch.ElapsedMilliseconds.ToString()});
return Task.FromResult(0);
});
await _next(context);
}
}
这是旧帖子,但这就是我处理此案的方式。 您可以在调用授权方法之前将tenantId存储在localstorage中 并在httpLoaderFactory中从localstorage获取tenantId并设置OpenIdConfiguration的customParamsCodeRequest。不幸的是,在代码流上调用authorize()或checkAuth()方法时,我无法传递customParams,这只能通过隐式流实现。
Angular oidc 示例:
localStorage.setItem("tenantId", "my_tenant_id");
this.oidcSecurityService.authorize();
应用程序模块:
export const httpLoaderFactory = (http: HttpClient) => {
let config$: Observable<OpenIdConfiguration> = new Observable((s) => {
let tenantId = localStorage.getItem("tenantId") ?? "";
let c: OpenIdConfiguration = {
authority: "identityserver",
redirectUrl: window.location.origin + "/",
postLogoutRedirectUri: window.location.origin,
clientId: "aaa",
scope: "openid profile api1",
responseType: "code",
silentRenew: true,
useRefreshToken: true,
logLevel: LogLevel.Debug,
customParamsCodeRequest: { tenantId: tenantId },
};
return s.next(c);
});
return new StsConfigHttpLoader(config$);
};
AppModule 导入:
imports: [
...
AuthModule.forRoot({
loader: {
provide: StsConfigLoader,
useFactory: httpLoaderFactory,
deps: [HttpClient],
},
}),
],