- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在开发一个 Blazor 应用程序,它是一个 Multi-Tenancy 应用程序。
我正在使用 Sustainsys.Saml2.AspNetCore2 包。
我有一个正在运行的测试 Blazor 应用程序,它可以针对测试进行授权 https://stubidp.sustainsys.com IdP 或测试 OKTA IdP 帐户。到目前为止一切都很好!
我想获得一个能够同时使用两个 IdP 的代码示例。我不确定如何通过 services.AddAuthentication().AddSaml2(options => 或其他方式配置 2 个 IdP。我知道如何配置一个但不超过一个。
这将帮助我了解如何为我们的 Multi-Tenancy 应用程序设置不同的 IdP。
我的后续问题是是否可以在运行时将 IdP 添加到我的应用程序中,而不是在应用程序启动并运行 startup.cs 时。
谢谢!
最佳答案
经过大量挖掘,我找到了我问题的答案。将来我将在 GitHub 上发布一个完整的 Blazor 和 WebForms 测试应用程序,但就目前而言,这里有一些关键信息。
创建 Blazor 应用程序时,请确保您允许使用个人用户帐户登录,以获得登录和外部登录 (Saml) 的正确脚手架。如果您当前的 Blazor 应用程序没有身份脚手架,请按照在线步骤将脚手架添加到您的应用程序。
在 Blazor 中,如果您希望每个 IdP 拥有单独的 SAML 模块,您将多次调用 .AddSaml2 并为每个 .AddSaml2 分配一个 IdP (options.IdentityProviders.Add...)。此配置的关键是在构造函数中命名每个 Saml2 提供程序,例如 .AddSaml2("Client1", "Client1", options => 和 .AddSaml2("Client2", "Client2", options =>。当你这样做时,您将看到这些模块名称中的每一个都显示为右侧登录页面上的按钮。
如果您希望在一个模块中包含多个 IdP,那么您可以使用如下配置调用 .AddSaml2 一次:
// OKTA example that works
//options.SPOptions.EntityId = new EntityId("https://localhost:44312/Okta"); // MSJ - Change to the current URL (proper port) -https://localhost:44312/Saml2
options.SPOptions.EntityId = new EntityId("https://example.com/"); // Dummy entry
// options.SPOptions.ModulePath = "/Okta"; // Don't need this, default is "Saml2"
options.SPOptions.ReturnUrl = new Uri("/counter", UriKind.Relative); // Note used if RelayStateUsedAsReturnUrl set below is true
options.Notifications.AcsCommandResultCreated = AcsCommandResultCreated; // Needed to intercept the command and add the LoginProvider for the tenant if IdP initiated login
options.Notifications.GetIdentityProvider = GetIdentityProvider;
options.Notifications.SelectIdentityProvider = SelectIdentityProvider;
//options.Notifications.MetadataCreated = MetadataCreated;
options.Notifications.AuthenticationRequestCreated = AuthenticationRequestCreated;
options.Notifications.Unsafe.TokenValidationParametersCreated = TokenValidationParametersCreated;
options.SPOptions.ServiceCertificates.Add(new X509Certificate2("Sustainsys.Saml2.Tests.pfx", "")); // Sustainsys.Saml2.Tests.pfx - no password on this pfx file
// For now, turned off Assertion encryption
options.IdentityProviders.Add(new IdentityProvider(new EntityId("http://www.okta.com/exk2edycw57Obmc5i5d7"), options.SPOptions)
{
MetadataLocation = "https://dev-60124262.okta.com/app/exk2edycw57Obmc5i5d7/sso/saml/metadata", // Need this since EntityID is different than metadata location
LoadMetadata = true,
AllowUnsolicitedAuthnResponse = true, // Need this for IdP initiated login
// Need this as well for IdP initiated login to tell SAML2 to redirect to the ExternalLogin page in the Account folder
RelayStateUsedAsReturnUrl = true, // In OKTA or others, ensure the relay state is set to /Identity/Account/ExternalLogin?returnUrl=%2F&handler=Callback to ensure proper routing
});
options.IdentityProviders.Add(new IdentityProvider(
new EntityId("https://stubidp.sustainsys.com/Metadata"), options.SPOptions)
{
LoadMetadata = true,
AllowUnsolicitedAuthnResponse = true,
RelayStateUsedAsReturnUrl = true, // Setting this always gives an error that the ReturnURL is not relative
});
//idp.SigningKeys.AddConfiguredKey(new X509Certificate2("okta.cert")); // Not needed since the cert is in the meta data.
saml2Options = options; // External reference for the options object
我在 Multi-Tenancy 环境中工作,所以我需要做更多的事情(处理通知)才能使事情正常进行。如果您只有一个 IdP,则不需要做这些额外的事情,因为它会正常工作。请注意,我计划动态加载这些 IdP,以便它们不会像本示例中提到的那样存在。这就是为什么我有“saml2Options”对象引用的原因,以便我可以稍后添加 IdP。
private void TokenValidationParametersCreated(TokenValidationParameters validationParameters, IdentityProvider idp, XmlElement xmlElement)
{
// ** Will need to replace the URL with the subdomain tenant code
// How do we get access to the Navigation Manager
validationParameters.ValidAudience = "https://localhost:44312/Saml2"; // Was /Okta
// validationParameters.ValidateAudience = false; // Could use this but set the ValidAudience
}
private void AuthenticationRequestCreated(Saml2AuthenticationRequest request, IdentityProvider a, IDictionary<string, string> dict)
{
// This does not seem to matter
// ** Will need to replace the URL with the subdomain tenant code
request.Issuer = new EntityId($"https://localhost:44312/Saml2"); // Was /Okta
}
private void MetadataCreated(EntityDescriptor request, Saml2Urls urls)
{
// ** Will need to replace the URL with the subdomain tenant code
// Not seeing this get called - do not worry about it
request.EntityId = new EntityId($"https://localhost:44312/Saml2");
}
private IdentityProvider SelectIdentityProvider(EntityId entityID, IDictionary<string, string> arg2)
{
return saml2Options.IdentityProviders[entityID];
}
private IdentityProvider GetIdentityProvider(EntityId entityID, IDictionary<string, string> arg2, IOptions arg3)
{
return saml2Options.IdentityProviders[entityID];
}
public void AcsCommandResultCreated(CommandResult arg1, Saml2Response arg2)
{
if (arg1.RelayData == null)
{
// Need to do this for IdP initiated logins. RelayData is null so we need to add the LoginProvider
var x = new Dictionary<string, string>();
x.Add("LoginProvider", "Saml2"); // Will always be "Saml2" if we stick with one Saml endpoint with multiple IdentityProviders
arg1.RelayData = x;
}
}
请注意,要使 IdP 启动登录工作,我需要将其放在 IdP 的 RelayState 中:
public IActionResult OnPost(string provider, string returnUrl = null)
{
// This is used for SP initiated login. So for this case, we know the URL and thus the tenantCode
// Hard coded here for testing but extract the tenant code from the URL here or from the external login button on the
// login page (pass it in)
// We are assuming one scheme (SSO provider) per tenant
string tenantCode = "Dev";
// Request a redirect to the external login provider.
var redirectUrl = Url.Page("./ExternalLogin", pageHandler: "Callback", values: new { returnUrl, tenantCode });
var properties = _signInManager.ConfigureExternalAuthenticationProperties(provider, redirectUrl);
// This is what they were talking about - add idp and scheme and THEN you will get the proper entityID in SelectIdentityProvider
properties.Items.Add("idp", "http://www.okta.com/exk2edycw57Obmc5i5d7"); // Put in the actual idp EntityID here - hardcoded here for testing
properties.Items.Add("scheme", "Saml2");
properties.Items.Add("tenant", "localhost"); // Used in notifications
return new ChallengeResult(provider, properties);
}
添加“idp”和“scheme”是必须的,以允许通知报告 Multi-Tenancy 环境中使用的实际 IdP。同样,如果您只需要处理一个 IdP,则无需执行所有这些操作。
关于sustainsys-saml2 - Sustainsys.SAML2 与 Multi-Tenancy 应用程序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69776923/
我是 C 语言新手,我编写了这个 C 程序,让用户输入一年中的某一天,作为返回,程序将输出月份以及该月的哪一天。该程序运行良好,但我现在想简化该程序。我知道我需要一个循环,但我不知道如何去做。这是程序
我一直在努力找出我的代码有什么问题。这个想法是创建一个小的画图程序,并有红色、绿色、蓝色和清除按钮。我有我能想到的一切让它工作,但无法弄清楚代码有什么问题。程序打开,然后立即关闭。 import ja
我想安装screen,但是接下来我应该做什么? $ brew search screen imgur-screenshot screen
我有一个在服务器端工作的 UDP 套接字应用程序。为了测试服务器端,我编写了一个简单的 python 客户端程序,它发送消息“hello world how are you”。服务器随后应接收消息,将
我有一个 shell 脚本,它运行一个 Python 程序来预处理一些数据,然后运行一个 R 程序来执行一些长时间运行的任务。我正在学习使用 Docker 并且我一直在运行 FROM r-base:l
在 Linux 中。我有一个 c 程序,它读取一个 2048 字节的文本文件作为输入。我想从 Python 脚本启动 c 程序。我希望 Python 脚本将文本字符串作为参数传递给 c 程序,而不是将
对于一个类,我被要求编写一个 VHDL 程序,该程序接受两个整数输入 A 和 B,并用 A+B 替换 A,用 A-B 替换 B。我编写了以下程序和测试平台。它完成了实现和行为语法检查,但它不会模拟。尽
module Algorithm where import System.Random import Data.Maybe import Data.List type Atom = String ty
我想找到两个以上数字的最小公倍数 求给定N个数的最小公倍数的C++程序 最佳答案 int lcm(int a, int b) { return (a/gcd(a,b))*b; } 对于gcd,请查看
这个程序有错误。谁能解决这个问题? Error is :TempRecord already defines a member called 'this' with the same paramete
当我运行下面的程序时,我在 str1 和 str2 中得到了垃圾值。所以 #include #include #include using namespace std; int main() {
这是我的作业: 一对刚出生的兔子(一公一母)被放在田里。兔子在一个月大时可以交配,因此在第二个月的月底,每对兔子都会生出两对新兔子,然后死去。 注:在第0个月,有0对兔子。第 1 个月,有 1 对兔子
我编写了一个程序,通过对字母使用 switch 命令将十进制字符串转换为十六进制,但是如果我使用 char,该程序无法正常工作!没有 switch 我无法处理 9 以上的数字。我希望你能理解我,因为我
我是 C++ 新手(虽然我有一些 C 语言经验)和 MySQL,我正在尝试制作一个从 MySQL 读取数据库的程序,我一直在关注这个 tutorial但当我尝试“构建”解决方案时出现错误。 (我正在使
仍然是一个初学者,只是尝试使用 swift 中的一些基本函数。 有人能告诉我这段代码有什么问题吗? import UIKit var guessInt: Int var randomNum = arc
我正在用 C++11 编写一个函数,它采用 constant1 + constant2 形式的表达式并将它们折叠起来。 constant1 和 constant2 存储在 std::string 中,
我用 C++ 编写了这段代码,使用运算符重载对 2 个矩阵进行加法和乘法运算。当我执行代码时,它会在第 57 行和第 59 行产生错误,非法结构操作(两行都出现相同的错误)。请解释我的错误。提前致谢:
我是 C++ 的初学者,我想编写一个简单的程序来交换字符串中的两个字符。 例如;我们输入这个字符串:“EXAMPLE”,我们给它交换这两个字符:“E”和“A”,输出应该类似于“AXEMPLA”。 我在
我需要以下代码的帮助: 声明 3 个 double 类型变量,每个代表三角形的三个边中的一个。 提示用户为第一面输入一个值,然后 将用户的输入设置为您创建的代表三角形第一条边的变量。 将最后 2 个步
我是新来的,如果问题不好请见谅 任务:将给定矩阵旋转180度 输入: 1 4 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 输出: 16 15 14 13 12 11
我是一名优秀的程序员,十分优秀!