Scu*_*eve 5 asp.net-mvc jwt azure-active-directory openid-connect azure-ad-graph-api
背景
我们在2016年开发了一个使用WS-Federation进行身份验证的应用程序,用于从内部部署AD获取声明.IT战略的方向已经发生变化,并且正朝着Azure AD(目前托管混合环境)发展.
我们正在使用OpenIDConnect将身份验证从WS-Fed迁移到AAD.让用户登录并使用新方法进行身份验证非常简单 - 正确配置,并发出身份验证挑战,而Robert是您母亲的兄弟.
问题
如果我的术语在这里错了,请纠正我; 我们需要通过默认的JWT从Active Directory中获取一些无法访问的属性(据我所知).因此,我们需要通过HTTP将JWT传递给Graph API,以从Active Directory获取我们想要的属性.
我知道格式正确且经过身份验证的请求可以提取必要的数据,因为我已经设法使用图形浏览器(AAD一个,而不是Microsoft Graph一个)来查看它.
问题
如果我的理解是正确的,我如何从ASP.Net中的HttpContext中提取JWT?如果我已经正确地掌握了所有这些较低级别的HTTP内容,我需要在Graph API请求的请求标头中包含JWT,我应该获得我需要的JSON文档作为响应.
(编辑,为了未来读者的利益:您实际上需要为您尝试访问的特定服务获取新令牌,在本例中为Azure AD.您可以使用代表流程或使用作为应用程序流程).
Request.Headers ["IdToken"]返回null,所以我想知道这里出了什么问题.
代码 这是我们在服务器启动时运行的身份验证配置:
public void Configuration(IAppBuilder app)
{
AntiForgeryConfig.SuppressIdentityHeuristicChecks = true;
//ConfigureAuth(app); //Old WsFed Auth Code
//start the quartz task scheduler
//RCHTaskScheduler.Start();
//Azure AD Configuration
app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);
app.UseCookieAuthentication(new CookieAuthenticationOptions());
app.UseOpenIdConnectAuthentication(
new OpenIdConnectAuthenticationOptions
{
//sets client ID, authority, and RedirectUri as obtained from web config
ClientId = clientId,
ClientSecret = appKey,
Authority = authority,
RedirectUri = redirectUrl,
//page that users are redirected to on logout
PostLogoutRedirectUri = redirectUrl,
//scope - the claims that the app will make
Scope = OpenIdConnectScope.OpenIdProfile,
ResponseType = OpenIdConnectResponseType.IdToken,
//setup multi-tennant support here, or set ValidateIssuer = true to config for single tennancy
TokenValidationParameters = new TokenValidationParameters()
{
ValidateIssuer = true,
SaveSigninToken = true
},
Notifications = new OpenIdConnectAuthenticationNotifications
{
AuthenticationFailed = OnAuthenticationFailed
}
}
);
}
Run Code Online (Sandbox Code Playgroud)
这是我用于制作GraphAPI请求的部分完整代码:
public static async Task<int> getEmployeeNumber(HttpContextBase context)
{
string token;
int employeeId = -1;
string path = "https://graph.windows.net/<domain>/users/<AAD_USER_ID>?api-version=1.6";
HttpWebRequest request = null;
request = (HttpWebRequest)HttpWebRequest.Create(path);
request.Method = "GET";
request.Headers.Add(context.GetOwinContext().Request.Headers["IdToken"]);
WebResponse response = await request.GetResponseAsync();
throw new NotImplementedException();
}
Run Code Online (Sandbox Code Playgroud)
好的,我花了几天的时间(以及一些来自Juunas的指针)来解决问题,但这绝对可以通过对此处的代码进行一些修改来实现。前述内容是Microsoft的OpenId指南。
我绝对建议阅读您的特定身份验证方案,并查看相关示例。
上面的内容可以帮助您,但是要从Graph API获得JWT(不要与Microsoft Graph混淆),您需要在进行身份验证时获取身份验证代码,并将其存储在令牌缓存中。
您可以从Microsoft(MIT许可证)的此示例中获得可用的令牌缓存。现在,就我个人而言,我发现这些样本被复杂的用例过于混淆了,而实际上它们应该概述基础知识,但这就是我自己。但是,这些足以使您接近。
现在来看一些代码。请允许我提请您注意“ ResponseType = CodeIdToken”。
public void ConfigureAuth(IAppBuilder app)
{
//Azure AD Configuration
app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);
app.UseCookieAuthentication(new CookieAuthenticationOptions());
app.UseOpenIdConnectAuthentication(
new OpenIdConnectAuthenticationOptions
{
//sets client ID, authority, and RedirectUri as obtained from web config
ClientId = clientId,
ClientSecret = appKey,
Authority = authority,
RedirectUri = redirectUrl,
//page that users are redirected to on logout
PostLogoutRedirectUri = redirectUrl,
//scope - the claims that the app will make
Scope = OpenIdConnectScope.OpenIdProfile,
ResponseType = OpenIdConnectResponseType.CodeIdToken,
//setup multi-tennant support here, or set ValidateIssuer = true to config for single tennancy
TokenValidationParameters = new TokenValidationParameters()
{
ValidateIssuer = true,
//SaveSigninToken = true
},
Notifications = new OpenIdConnectAuthenticationNotifications
{
AuthenticationFailed = OnAuthenticationFailed,
AuthorizationCodeReceived = OnAuthorizationCodeReceived,
}
}
);
}
Run Code Online (Sandbox Code Playgroud)
提供上述参数后,身份验证时将运行以下代码:
private async Task OnAuthorizationCodeReceived(AuthorizationCodeReceivedNotification context)
{
var code = context.Code;
ClientCredential cred = new ClientCredential(clientId, appKey);
string userObjectId = context.AuthenticationTicket.Identity.FindFirst("http://schemas.microsoft.com/identity/claims/objectidentifier").Value;
AuthenticationContext authContext = new AuthenticationContext(authority, new NaiveSessionCache(userObjectId));
// If you create the redirectUri this way, it will contain a trailing slash.
// Make sure you've registered the same exact Uri in the Azure Portal (including the slash).
Uri uri = new Uri(HttpContext.Current.Request.Url.GetLeftPart(UriPartial.Path));
AuthenticationResult result = await authContext.AcquireTokenByAuthorizationCodeAsync(code, uri, cred, "https://graph.windows.net");
}
Run Code Online (Sandbox Code Playgroud)
这将为令牌缓存提供可以传递给Graph API的代码。从这里,我们可以尝试使用Graph API进行身份验证。
string path = "https://graph.windows.net/me?api-version=1.6";
string tenant = System.Configuration.ConfigurationManager.AppSettings["Tenant"];
string userObjectId = ClaimsPrincipal.Current.FindFirst("http://schemas.microsoft.com/identity/claims/objectidentifier").Value;
string resource = "https://graph.windows.net";
AuthenticationResult result = null;
string authority = String.Format(System.Globalization.CultureInfo.InvariantCulture, System.Configuration.ConfigurationManager.AppSettings["Authority"], tenant);
ClientCredential cc = new ClientCredential(ConfigurationManager.AppSettings["ClientId"], ConfigurationManager.AppSettings["ClientSecret"]);
AuthenticationContext auth = new AuthenticationContext(authority, new NaiveSessionCache(userObjectId));
try
{
result = await auth.AcquireTokenSilentAsync(resource,
ConfigurationManager.AppSettings["ClientId"],
new UserIdentifier(userObjectId, UserIdentifierType.UniqueId)).ConfigureAwait(false);
}
catch (AdalSilentTokenAcquisitionException e)
{
result = await auth.AcquireTokenAsync(resource, cc, new UserAssertion(userObjectId));
}
Run Code Online (Sandbox Code Playgroud)
获得身份验证令牌后,可以通过Http Request将其传递给Graph API(这是简单的部分)。
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(path);
request.Method = "GET";
request.Headers.Set(HttpRequestHeader.Authorization, "Bearer " + result.AccessToken);
WebResponse response = request.GetResponse();
System.IO.Stream dataStream = response.GetResponseStream();
Run Code Online (Sandbox Code Playgroud)
从这里开始,您将拥有一个数据流,可以将其传递到流读取器中,取出JSON并进行任何您想做的事情。就我而言,我只是在寻找目录中的用户数据,但不包含在Azure AD身份验证发出的默认声明中。因此,就我而言,我要呼叫的网址是
"https://graph.windows.net/me?api-version=1.6"
Run Code Online (Sandbox Code Playgroud)
如果您需要对目录进行更深入的研究,建议您使用Graph Explorer。这将帮助您构建API调用。再说一次,我发现Microsoft文档有点晦涩(如果您想看一些有趣的东西,请查看Twilio API)。但是,一旦您弄清楚了,它实际上并没有那么糟糕。
| 归档时间: |
|
| 查看次数: |
915 次 |
| 最近记录: |