我有三个应用程序,它们都使用不同的.NET方法(我不知道一个更好的词)。我有一个.NET核心3.1 Web应用程序,一个.NET框架4.8 MVC Web应用程序,和一个.NET框架4.6 Web窗体应用程序。
这三款应用都要求我使用PKCE(Proof Key for Code Exchange,用于代码交换的验证密钥)。这三款应用都使用Amazon AWS Cognito进行身份验证和授权。除了两款非.NET Core应用不使用PKCE之外,其他一切都运行良好,我需要它们使用PKCE。
- 好的,我在这里的主要想法是,可能有一些“轻松”的方法,我可以通过Startup.Auth.cs文件或定义OIDC Auth* 之类的文件向.NET Framework应用程序添加PKCE支持。
我的所作所为
我已经能够找到一些关于如何向站点添加PKCE的在线文章,但是它们都是向查询字符串添加必要位的手动机制。
- How to secure the Cognito login flow with a state nonce and PKCE
- Authorize endpoint
- ASP.NET Core using Proof Key for Code Exchange (PKCE)
NET Core这篇文章对我了解.NET Core应用程序的工作方式特别有用,但对其他两个应用程序没有帮助。总的来说,这个过程似乎分为以下步骤:
1.创建一个代码验证器,称之为验证器。
1.代码验证器和base64编码SHA 256。称之为挑战。
1.将其添加到我们发送到“authorize”端点的查询字符串中,沿着添加code_challenge_method,对于Cognito,该方法必须设置为S256。
1.将值为VERIFIER的Code_Verifier添加到我们发送到“token”端点的查询字符串中。
本质上,我们可以手动将以下内容添加到调用“authorize”端点的查询字符串中:“&代码挑战=挑战&代码挑战方法=S256”。
以及调用“token”端点的查询字符串:“&代码验证器=验证器”.(I'm pretty sure this token endpoint is a POST.)
我想就是这样。所以,我可以手动地将这些东西添加到这些调用中。然而,我更愿意让.NET框架神奇地为我做这些工作。
因此,我的总问题是:是否有办法修改.NET代码?我必须通过修改代码而不是手动添加来添加PKCE。
我已经搜索了Web、Microsoft站点,并且我已经摆弄了实际的代码,但是我没有找到任何在这些方法中添加PKCE的机制。
我的代码示例:
.NET框架Web窗体应用程序:
public void ConfigureAuth(IAppBuilder app)
{
app.SetDefaultSignInAsAuthenticationType(DefaultAuthenticationTypes.ApplicationCookie);
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
CookieManager = new SystemWebCookieManager()
});
ConfigureIdentityProviders(app, DefaultAuthenticationTypes.ApplicationCookie);
}
private void ConfigureIdentityProviders(IAppBuilder app, string signInAsType)
{
var saveTokens = true;
var validateIssuer = true;
var saveTokensValue = ConfigurationManager.AppSettings["Cognito.SaveTokens"];
if (!string.IsNullOrEmpty(saveTokensValue))
{
saveTokens = bool.TryParse(saveTokensValue, out var outResult) && outResult;
}
var validateIssuerValue = ConfigurationManager.AppSettings["Cognito.TokenValidationParameters.ValidateIssuer"];
if (!string.IsNullOrEmpty(validateIssuerValue))
{
validateIssuer = bool.TryParse(validateIssuerValue, out var outResult) && outResult;
}
app.UseCustomOidcAuthentication(
new OpenIdConnectAuthenticationOptions
{
ClientId = ConfigurationManager.AppSettings["Cognito.ClientId"],
ResponseType = ConfigurationManager.AppSettings["Cognito.ResponseType"],
Authority = ConfigurationManager.AppSettings["Cognito.Authority"],
MetadataAddress = ConfigurationManager.AppSettings["Cognito.MetadataAddress"],
ClientSecret = ConfigurationManager.AppSettings["Cognito.ClientSecret"],
RedirectUri = ConfigurationManager.AppSettings["Cognito.RedirectUri"],
SaveTokens = saveTokens,
TokenValidationParameters = new TokenValidationParameters
{
NameClaimType = ConfigurationManager.AppSettings["Cognito.TokenValidationParameters.NameClaimType"],
RoleClaimType = ConfigurationManager.AppSettings["Cognito.TokenValidationParameters.RoleClaimType"],
ValidateIssuer = validateIssuer
},
Notifications = new OpenIdConnectAuthenticationNotifications
{
RedirectToIdentityProvider = async (context) =>
{
var removePortOnRedirectIdentifierValue = ConfigurationManager.AppSettings["Cognito.RemovePortOnRedirectToIdentityProvider"];
var convertResult = bool.TryParse(removePortOnRedirectIdentifierValue, out var removePortOnRedirectIdentifier);
if (removePortOnRedirectIdentifier && convertResult)
{
var builder = new UriBuilder(context.ProtocolMessage.RedirectUri)
{
Scheme = "https",
Port = -1
};
context.ProtocolMessage.RedirectUri = builder.ToString();
}
}
},
Scope = ConfigurationManager.AppSettings["Cognito.Scope"],
SignInAsAuthenticationType = signInAsType
}
);
}
我的.NET框架MVC应用程序:
public void ConfigureAuth(IAppBuilder app)
{
var loginPath = AuthorizationSettings.Instance.LoginPath;
if (string.IsNullOrEmpty(loginPath))
throw new ArgumentNullException("No value specified for EiHubSettings LoginPath");
// Configure the db context, user manager and signin manager to use a single instance per request
app.CreatePerOwinContext(SecurityDbContext.Create);
app.CreatePerOwinContext<SecurityUserManager>(SecurityUserManager.Create);
app.CreatePerOwinContext<SecurityRoleManager>(SecurityRoleManager.Create);
app.CreatePerOwinContext<SecuritySignInManager>(SecuritySignInManager.Create);
// Enable the application to use a cookie to store information for the signed in user
// and to use a cookie to temporarily store information about a user logging in with a third party login provider
// Configure the sign in cookie
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
LoginPath = new PathString(loginPath),
CookieManager = new SystemWebCookieManager(),
ExpireTimeSpan = TimeSpan.FromSeconds(
Convert.ToInt32(ConfigurationManager.AppSettings["Cognito.CookieLifetimeInSeconds"])),
Provider = new CookieAuthenticationProvider
{
// Enables the application to validate the security stamp when the user logs in.
// This is a security feature which is used when you change a password or add an external login to your account.
OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<SecurityUserManager, SecurityUser, int>(
validateInterval: TimeSpan.FromMinutes(30),
regenerateIdentityCallback: (manager, user) => user.CreateIdentityAsync(manager),
getUserIdCallback: (user) => user.GetUserId<int>())
}
});
app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
// Enables the application to temporarily store user information when they are verifying the second factor in the two-factor authentication process.
app.UseTwoFactorSignInCookie(DefaultAuthenticationTypes.TwoFactorCookie, TimeSpan.FromMinutes(5));
// Enables the application to remember the second login verification factor such as phone or email.
// Once you check this option, your second step of verification during the login process will be remembered on the device where you logged in from.
// This is similar to the RememberMe option when you log in.
app.UseTwoFactorRememberBrowserCookie(DefaultAuthenticationTypes.TwoFactorRememberBrowserCookie);
if(AppSettingsConfigSingleton.UsesCognito)
{
ConfigureIdentityProviders(app, DefaultAuthenticationTypes.ApplicationCookie);
}
}
private void ConfigureIdentityProviders(IAppBuilder app, string signInAsType)
{
var saveTokens = true;
var validateIssuer = true;
var saveTokensValue = ConfigurationManager.AppSettings["Cognito.SaveTokens"];
if (!string.IsNullOrEmpty(saveTokensValue))
{
saveTokens = bool.TryParse(saveTokensValue, out var outResult) && outResult;
}
var validateIssuerValue = ConfigurationManager.AppSettings["Cognito.TokenValidationParameters.ValidateIssuer"];
if (!string.IsNullOrEmpty(validateIssuerValue))
{
validateIssuer = bool.TryParse(validateIssuerValue, out var outResult) && outResult;
}
app.UseCustomOidcAuthentication(
new OpenIdConnectAuthenticationOptions
{
ClientId = ConfigurationManager.AppSettings["Cognito.ClientId"],
ResponseType = ConfigurationManager.AppSettings["Cognito.ResponseType"],
Authority = ConfigurationManager.AppSettings["Cognito.Authority"],
MetadataAddress = ConfigurationManager.AppSettings["Cognito.MetadataAddress"],
ClientSecret = ConfigurationManager.AppSettings["Cognito.ClientSecret"],
RedirectUri = ConfigurationManager.AppSettings["Cognito.RedirectUri"],
SaveTokens = saveTokens,
Notifications = new OpenIdConnectAuthenticationNotifications
{
SecurityTokenValidated = context =>
{
var redirectUri = "/account/openidlogincallback";
if (!string.IsNullOrEmpty(context.AuthenticationTicket.Properties.RedirectUri))
{
redirectUri += $"?returnUrl={context.AuthenticationTicket.Properties.RedirectUri}";
}
context.AuthenticationTicket.Properties.RedirectUri = redirectUri;
return Task.FromResult(0);
},
RedirectToIdentityProvider = context =>
{
var removePortOnRedirectIdentifierValue = ConfigurationManager.AppSettings["Cognito.RemovePortOnRedirectToIdentityProvider"];
var convertResult = bool.TryParse(removePortOnRedirectIdentifierValue, out var removePortOnRedirectIdentifier);
if (removePortOnRedirectIdentifier && convertResult)
{
var builder = new UriBuilder(context.ProtocolMessage.RedirectUri)
{
Scheme = "https", Port = -1
};
context.ProtocolMessage.RedirectUri = builder.ToString();
}
return Task.FromResult(0);
}
},
TokenValidationParameters = new TokenValidationParameters
{
NameClaimType = ConfigurationManager.AppSettings["Cognito.TokenValidationParameters.NameClaimType"],
RoleClaimType = ConfigurationManager.AppSettings["Cognito.TokenValidationParameters.RoleClaimType"],
ValidateIssuer = validateIssuer
},
Scope = ConfigurationManager.AppSettings["Cognito.Scope"],
SignInAsAuthenticationType = signInAsType
}
);
}
NET Core 3.1应用程序(是的,我知道我们需要升级到.NET 6)有一个“内置”的机制来添加PKCE(这让我困惑了很长一段时间,直到我看到这个--这个选项在我的代码中没有显式设置,但正如您所看到的,它在默认情况下是打开的):
因此,我希望. NETFramework中也有类似的东西
1条答案
按热度按时间s4n0splo1#
在
StartUp
类中:在
ConfigureIdentityProviders
中在Startup
中在我的
CustomOidcHandler
文件中,GetTokens
方法:因此,唯一的方法是“手动”添加它。