C# 如何获取与外部api集成测试的访问令牌
对于集成测试,我有一个授权的.NET Core 2.2控制器,它正在调用另一个授权控制器(不同的项目)或外部api(如Microsoft Graph) 这两个API都是针对Azure AD进行身份验证的。在所有控制器操作中,我们都需要经过身份验证的用户。 我们可以通过基于用户名和密码(grant_type=password)获得一个令牌来进入第一个api。当调用继续到第二个api时,由于交互式登录提示(我们使用ADAL),调用中断 通常,用户使用openid connect进行身份验证,然后我们获得身份验证代码,并使用身份验证代码获取accesstoken+刷新令牌。使用刷新令牌,我们可以获得第二个api的访问令牌 我们创建了一个带有默认值控制器的小样本项目来解释我们的问题 在使用本机应用程序注册调用第一个api之前获取访问令牌:C# 如何获取与外部api集成测试的访问令牌,c#,azure,asp.net-core,azure-active-directory,adal,C#,Azure,Asp.net Core,Azure Active Directory,Adal,对于集成测试,我有一个授权的.NET Core 2.2控制器,它正在调用另一个授权控制器(不同的项目)或外部api(如Microsoft Graph) 这两个API都是针对Azure AD进行身份验证的。在所有控制器操作中,我们都需要经过身份验证的用户。 我们可以通过基于用户名和密码(grant_type=password)获得一个令牌来进入第一个api。当调用继续到第二个api时,由于交互式登录提示(我们使用ADAL),调用中断 通常,用户使用openid connect进行身份验证,然后我们
public static async Task<string> AcquireTokenAsync(string username, string password)
{
var aadInstance = "https://login.windows.net/{0}";
var tenantId = "put id here";
var authority = string.Format(aadInstance, tenantId);
var clientId = "clientid here";
var resource = "put resource here";
var client = new HttpClient();
var tokenEndpoint = $"https://login.microsoftonline.com/{tenantId}/oauth2/token";
var body = $"resource={resource}&client_id={clientId}&grant_type=password&username={username}&password={password}";
var stringContent = new StringContent(body, Encoding.UTF8, "application/x-www-form-urlencoded");
var result = await client.PostAsync(tokenEndpoint, stringContent).ContinueWith((response) =>
{
return response.Result.Content.ReadAsStringAsync().Result;
});
JObject jobject = JObject.Parse(result);
var token = jobject["access_token"].Value<string>();
return token;
}
公共静态异步任务AcquireTokenAsync(字符串用户名、字符串密码)
{
var aadInstance=”https://login.windows.net/{0}";
var tenantId=“将id放在此处”;
var authority=string.Format(aadInstance,tenantId);
var clientId=“clientId here”;
var resource=“将资源放在此处”;
var client=新的HttpClient();
var-tokenpoint=$”https://login.microsoftonline.com/{tenantId}/oauth2/token”;
var body=$“resource={resource}&client_id={clientId}&grant_type=password&username={username}&password={password}”;
var stringContent=新的stringContent(body,Encoding.UTF8,“application/x-www-form-urlencoded”);
var result=wait client.PostAsync(令牌端点,stringContent).ContinueWith((响应)=>
{
返回response.Result.Content.ReadAsStringAsync().Result;
});
JObject=JObject.Parse(结果);
var token=jobject[“access_token”].Value();
返回令牌;
}
第一个API:
[Authorize]
[HttpGet]
public async Task<IActionResult> Get()
{
string name = User.Identity.Name;
var result = await AcquireTokenSilentWithImpersonationAsync();
string BaseUrl = "https://localhost:44356/";
var client = new HttpClient
{
BaseAddress = new Uri(BaseUrl)
};
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", result.AccessToken);
var url = "api/values";
HttpResponseMessage response = await client.GetAsync(url);
switch (response.StatusCode)
{
case HttpStatusCode.OK:
int x = 1;
break;
default:
throw new HttpRequestException($"Error - {response.StatusCode} in response with message '{response.RequestMessage}'");
}
return Ok();
}
[授权]
[HttpGet]
公共异步任务Get()
{
字符串名称=User.Identity.name;
var result=await AcquireTokenSilentWithImpersonationAsync();
字符串BaseUrl=”https://localhost:44356/";
var client=新的HttpClient
{
BaseAddress=新Uri(BaseUrl)
};
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(新的MediaTypeWithQualityHeaderValue(“应用程序/json”);
client.DefaultRequestHeaders.Authorization=新的AuthenticationHeaderValue(“Bearer”,result.AccessToken);
var url=“api/values”;
HttpResponseMessage response=wait client.GetAsync(url);
开关(响应状态代码)
{
案例HttpStatusCode.OK:
int x=1;
打破
违约:
抛出新的HttpRequestException($“Error-{response.StatusCode}以响应消息“{response.RequestMessage}”);
}
返回Ok();
}
private const string BackendResource=“此处的第二个api资源”;
///
///有关更多信息:https://docs.microsoft.com/en-us/azure/active-directory/develop/active-directory-devhowto-adal-error-handling
///
///
公共异步任务AcquireTokenSilentWithImpersonationAsync()
{
const string ClientId=“此处第一个api的客户端id”;
const string ClientSecret=“此处第一个api的秘密”;
ClientCredential=新的ClientCredential(ClientId,ClientSecret);
字符串userObjectId=\u httpContextAccessor.HttpContext.User.FindFirst(“http://schemas.microsoft.com/identity/claims/objectidentifier)价值;
var authContext=GetAuthenticationContext(userObjectId);
AuthenticationResult authResult=null;
尝试
{
authResult=等待authContext.AcquireTokenSilentAsync(后端资源、凭证、新用户标识符(userObjectId、UserIdentifierType.UniqueId));
}
捕获(AdalSilentTokenAcquisitionException ex)
{
//例外:AdalSilentTokenAcquisitionException
//当缓存中没有令牌或所需刷新失败时导致。
//措施:案例1,可通过交互式请求解决。
尝试
{
authResult=等待authContext.AcquireTokenAsync(后端资源,客户端ID,新Uri(“https://backurl.org)、新平台参数()、新用户标识符(userObjectId、UserIdentifierType.UniqueId));
}
捕获(异常exs)
{
投掷;
}
}
接住(二语)
{
//例外:词汇感知
//表示由ADAL.NET生成的库异常。
//e.ErrorCode包含错误代码。
//措施:案例2,无法通过交互式请求解决。
//尝试在时间间隔或用户操作后重试。
//示例错误:网络不可用,默认情况。
投掷;
}
返回结果;
}
第二个api:
[Authorize]
[HttpGet]
public ActionResult<IEnumerable<string>> Get()
{
string name = User.Identity.Name;
return new string[] { "value1", "value2" };
}
[授权]
[HttpGet]
公共行动结果获取()
{
字符串名称=User.Identity.name;
返回新字符串[]{“value1”,“value2”};
}
您需要在Web API中使用代表流(而不是交互式令牌获取,需要)
如果您想使用ADAL.NET,这里有一个示例:
但我现在建议您使用MSAL.NET。样本为:,文档为:
还要注意的是,对于Web api,我们不使用OIDC(这是为了登录用户),而是使用JWT承载中间件来访问本地应用程序中的第一个api应用程序,所以第一个api应用程序的缓存中没有用户/令牌/刷新令牌。所以AcquireTokenSilentAsync在您的场景中不起作用。我知道这不起作用。这就是我们提出这个问题的原因;-)。通常我们不使用本机但开放id连接。但这是交互式的。我们使用OIDC,但是对于集成测试来说,交互式是不可能的,所以我们正在检查一些替代方案。没有OIDC(集成测试),我们就无法进行海外建筑运营管理局呼叫。我们需要用户的上下文。问微软这个问题
[Authorize]
[HttpGet]
public ActionResult<IEnumerable<string>> Get()
{
string name = User.Identity.Name;
return new string[] { "value1", "value2" };
}