如何使用 OAuth 2 从 ADFS C# 获取已登录用户或应用程序池标识用户的 Jwt Token
如何使用 OAuth 2 从 ADFS 生成应用程序池标识或已登录用户的 Jwt 安全令牌
引言
在本文中,我们将学习如何使用 OAuth 2 从 ADFS 为应用程序池标识或已登录用户生成 Jwt 安全令牌。
背景
如果您有兴趣,请阅读应用程序池标识。现在,将用户凭据保存在任何配置文件或其他资源文件中有点危险。相反,我们可以使用应用程序池标识功能。
它比将凭据以任何形式存储在源代码中更安全。
请参阅此链接。
Using the Code
我构建并将 NuGet 包推送到 NuGet 服务器,名为“OAuth2 Authorization Provider 1.0.0”,它已完成所有前期工作。
用于安装软件包的 NuGet 包管理器命令:Install-Package OAuth2.Authorization
您需要做的就是将适当的 ADFS OAuth 2 配置放在 web 或 app 配置文件中,并从上面提到的 NuGet 包中调用辅助函数。
有关 OAuth 2 规范的更多信息,请访问此链接。
在本文中,我们使用两种方法来获取 JWT 令牌。它们是
- Adal 流
- OAuth 代码流
方法 1:使用 Adal 流
配置依赖项
<!--Global appSettings-->
<add key="AdfsInstance" value=""/>
<add key="ClientId" value=""/>
<add key="Resource" value=""/>
<add key="RedirectUri" value="https://:56194/redirect"/>
<add key="AdfsAuthorityUrl" value="https://{0}/adfs/ls/{1}" />
在 appSettings
部分中提供上述配置值,并调用“OAuth2 Authorization Provider 1.0.0” NuGet 包中提供的以下函数调用。
AdfsAuthorization.GetAdfsOAuthJwtAccessTokenForWinAppUserUsingAdal()
工作原理
在内部,它使用 Microsoft.IdentityModel.Clients.ActiveDirectory
NuGet 包为 ADFS 创建身份验证上下文。身份验证上下文需要 resource
、clientId
、redirectUri
、adfsInstance
和 AuthorityUrl
参数,以便为已登录用户提供 Jwt 令牌。
完整代码
if (!AdfsConfiguration.IsInitialized) throw new SecurityException
(Constants.AdfsConfigurationInitilizationExceptionMessage);
if (string.IsNullOrEmpty(AdfsConfiguration.AdfsAuthorityUrl))
throw new SecurityException
(Constants.AdfsConfigurationAdfsAuthorityUrlInitilizationExceptionMessage);
try
{
var authenticationContext = new AuthenticationContext
(string.Format(AdfsConfiguration.AdfsAuthorityUrl, AdfsConfiguration.AdfsInstance,
AdfsConfiguration.Resource), false);
var asyncRequest = authenticationContext.AcquireTokenAsync
(AdfsConfiguration.Resource, AdfsConfiguration.ClientId,
new Uri(AdfsConfiguration.RedirectUri), new PlatformParameters(PromptBehavior.Auto));
var accessToken = asyncRequest.Result.AccessToken;
return accessToken;
}
catch (Exception exp)
{
var additionalInfo = $" additionalInfo : [authenticationContext :
{string.Format(AdfsConfiguration.AdfsAuthorityUrl, AdfsConfiguration.AdfsInstance,
AdfsConfiguration.Resource)}]";
throw new SecurityException
($"AdfsAuthorization.GetAdfsOAuthJwtAccessTokenForWinAppUserUsingAdal is failed,
{additionalInfo}", exp);
}
方法 2:使用 OAuth2 授权代码流
它有两个过程
- 首先,我们需要根据
clientId
、resource
和redirecturi
(已在 ADFS 服务器中为应用程序配置)从 ADFS 服务器获取 OAuth 代码。 - 成功从 ADFS 获取 Auth 代码后,我们必须再次将 Auth 代码交给 ADFS 服务器,以为相关的 ADFS 用户提供 Jwt 令牌。
配置依赖项
<!--Global-->
<add key="AdfsInstance" value=""/>
<add key="ClientId" value=""/>
<add key="Resource" value=""/>
<add key="RedirectUri" value="https://:56194/redirect"/>
<add key="AdfsTokenServiceUrl" value="https://{0}/adfs/oauth2/token/"/>
在 appSetting
部分中提供上述配置,并调用以下代码行,您就完成了(已在 NuGet 包中提供)。
await AuthorizationManager.GetAdfsOAuthJwtAccessTokenForWinAppUserUsingAuthCodeAsync()
工作原理
要获取授权码,您需要通过提供正确的 ADFS 身份验证 URL 来发出 HttpClient
请求。
完整代码
var authUrl = string.Format(AdfsConfiguration.AdfsAuthUrl, AdfsConfiguration.AdfsInstance,
AdfsConfiguration.ClientId, AdfsConfiguration.Resource,
AdfsConfiguration.UrlEncodedRedirectUri);
var authCode = "";
try
{
do
{
var result = await Client.GetAsync(authUrl);
await result.Content.ReadAsStringAsync();
IEnumerable<string> values;
if (result.Headers.TryGetValues("location", out values))
{
foreach (string s in values)
{
if (s.Contains("code="))
{
authUrl = "";
authCode = s.Substring(s.IndexOf("code=", StringComparison.Ordinal) + 5);
}
else
{
authUrl = s;
}
}
}
else
{
authUrl = "";
}
} while (!string.IsNullOrEmpty(authUrl));
return authCode;
}
catch (Exception exp)
{
var additionalInfo = $"additionalInfo : [authUrl: {authUrl}]";
throw new SecurityException
($"AdfsAuthorization.GetAuthCodeForWinAppUserAsync is failed, {additionalInfo}", exp);
}
获得 Authcode
后,使用 WebClient
获取加密格式的 Jwt 令牌。 如果你想看看它包含什么,那么你需要有适当的证书来验证和查看它有什么。 NuGet 中也提供了此功能。
完整代码
var client = new WebClient();
try
{
if (AdfsConfiguration.UseProxy == "Y")
{
var proxyObject = new WebProxy("Proxy", 80)
{ Credentials = CredentialCache.DefaultNetworkCredentials };
client.Proxy = proxyObject;
}
//Uri address = new Uri(String.Format("https://{0}/adfs/oauth2/token/", AdfsInstance));
Uri address = new Uri
(string.Format(AdfsConfiguration.AdfsTokenServiceUrl, AdfsConfiguration.AdfsInstance));
Uri redirectAddress = new Uri(AdfsConfiguration.RedirectUri);
NameValueCollection values = new NameValueCollection
{
{"client_id", AdfsConfiguration.ClientId},
{"grant_type", "authorization_code"},
{"code", code},
{"redirect_uri", redirectAddress.ToString()}
};
byte[] responseBytes = client.UploadValues(address, "POST", values);
string response = System.Text.Encoding.UTF8.GetString(responseBytes);
return response;
}
catch (Exception exp)
{
var additionalInfo = $" additionalInfo :
[address: {string.Format(AdfsConfiguration.AdfsTokenServiceUrl,
AdfsConfiguration.AdfsInstance) }, redirect Uri :{AdfsConfiguration.RedirectUri}]";
throw new SecurityException($"AdfsAuthorization.GetAdfsOAuthTokenByAuthCode is failed,
{additionalInfo}", exp);
}
finally
{
client.Dispose();
}
这就是从 ADFS 服务器为已登录用户或应用程序池标识获取 Jwt 令牌的全部内容。
除了本文之外,我还附加了示例测试工具来进行试用(Winform - 测试应用程序)。
历史
- 版本 1.0.1