Web Api 到 Signalr Azure 令牌无法正常工作
Web Api to Signalr Azure token not working
我有一个 Asp.Net Web Api (Api1) 需要向 Signalr Realtime Api (Api2) 发送消息.我正在尝试使用 Azure AD 不记名令牌进行身份验证。 Api1 的客户端是一个 JavaScript 客户端,它使用 ADAL.js 从 Azure 获取令牌。
var authContext = new AuthenticationContext({
tenant: tenantId,
clientId: jsclientId,
postLogoutRedirectUri: window.location.origin,
cacheLocation: 'localStorage',
endpoints: {
api1Url: api1ResourceUri
}
});
authContext.acquireToken(jsclientId, function (error, token) {
if (error || !token) {
authContext.clearCache();
authContext.login();
}
});
JS 客户端在授权 header 中将此令牌附加到对 Api1 的所有 Api 调用。在 Api1 中,我使用以下代码从 Azure AD 获取访问令牌。
var userAssertion = new UserAssertion(bootstrapContext.Token, "urn:ietf:params:oauth:grant-type:jwt-bearer", userName);
var result = await authenticationContext.AcquireTokenAsync(api2ResourceId, new ClientCredential(api1clientId, api1clientSecret), userAssertion);
我将此访问令牌作为授权附加到请求中 header "Bearer tokenvalue"。在 Signalr Hub Owin Startup class 我有以下代码。
app.UseWindowsAzureActiveDirectoryBearerAuthentication(
new WindowsAzureActiveDirectoryBearerAuthenticationOptions
{
TokenValidationParameters = new TokenValidationParameters
{
ValidAudiences = api1Audiences,
SaveSigninToken = true
},
Tenant = configSection.TenantId
});
虽然中心上的 ClaimsIdentity 显示为已通过身份验证,但未设置用户身份。 identity.name 为空。看起来用户身份没有传递到 Signalr 中心。
您在 API 中没有获得用户身份,因为您是作为应用程序而不是用户对其进行身份验证。
仅获取资源和 ClientCredentials 的 acquireTokenAsync 重载用于客户端凭据流(a.k.a 仅限应用程序流)。
您需要做的是使用 On-behalf-of 流程将您为 API1 获得的令牌交换为 API2.
的令牌
所以在 API1 的 Startup.Auth,TokenValidation 参数中,将 Save SigninToken 设置为 true,如下所示:
app.UseOpenIdConnectAuthentication(
OpenIdConnectAuthenticationOptions
{
// ...
TokenValidationParameters = new TokenValidationParameters
{
SaveSigninToken = true
},
// ...
});
然后无论你想在哪里调用你的 API2,请执行以下操作:
ClientCredential clientCred = new ClientCredential(clientId, appKey);
var bootstrapContext = ClaimsPrincipal.Current.Identities.First().BootstrapContext as System.IdentityModel.Tokens.BootstrapContext;
string userName = ClaimsPrincipal.Current.FindFirst(ClaimTypes.Upn) != null ? ClaimsPrincipal.Current.FindFirst(ClaimTypes.Upn).Value : ClaimsPrincipal.Current.FindFirst(ClaimTypes.Email).Value;
string userAccessToken = bootstrapContext.Token;
UserAssertion userAssertion = new UserAssertion(bootstrapContext.Token, "urn:ietf:params:oauth:grant-type:jwt-bearer", userName);
result = await authContext.AcquireTokenAsync(api2ResourceId, clientCred, userAssertion);
在示例中查看:https://github.com/Azure-Samples/active-directory-dotnet-webapi-onbehalfof,特别是 ToDoService 的 Startup.Auth.cs 和 TodoListController.cs.
注意:此示例适用于本机应用程序 + 网络 api,您正在将其调整为网络应用程序 + 网络 api.
Edit - 通过在 JS acquireToken 调用中指定 API1 来确保您的 JS 代码正在为您的 API1 请求令牌,如下所示:
var authContext = new AuthenticationContext({
tenant: tenantId,
clientId: jsclientId,
postLogoutRedirectUri: window.location.origin,
cacheLocation: 'localStorage',
endpoints: {
api1Url: api1ResourceUri
}
});
authContext.acquireToken(api1clientId, function (error, token) {
if (error || !token) {
authContext.clearCache();
authContext.login();
}
});
我有一个 Asp.Net Web Api (Api1) 需要向 Signalr Realtime Api (Api2) 发送消息.我正在尝试使用 Azure AD 不记名令牌进行身份验证。 Api1 的客户端是一个 JavaScript 客户端,它使用 ADAL.js 从 Azure 获取令牌。
var authContext = new AuthenticationContext({
tenant: tenantId,
clientId: jsclientId,
postLogoutRedirectUri: window.location.origin,
cacheLocation: 'localStorage',
endpoints: {
api1Url: api1ResourceUri
}
});
authContext.acquireToken(jsclientId, function (error, token) {
if (error || !token) {
authContext.clearCache();
authContext.login();
}
});
JS 客户端在授权 header 中将此令牌附加到对 Api1 的所有 Api 调用。在 Api1 中,我使用以下代码从 Azure AD 获取访问令牌。
var userAssertion = new UserAssertion(bootstrapContext.Token, "urn:ietf:params:oauth:grant-type:jwt-bearer", userName);
var result = await authenticationContext.AcquireTokenAsync(api2ResourceId, new ClientCredential(api1clientId, api1clientSecret), userAssertion);
我将此访问令牌作为授权附加到请求中 header "Bearer tokenvalue"。在 Signalr Hub Owin Startup class 我有以下代码。
app.UseWindowsAzureActiveDirectoryBearerAuthentication(
new WindowsAzureActiveDirectoryBearerAuthenticationOptions
{
TokenValidationParameters = new TokenValidationParameters
{
ValidAudiences = api1Audiences,
SaveSigninToken = true
},
Tenant = configSection.TenantId
});
虽然中心上的 ClaimsIdentity 显示为已通过身份验证,但未设置用户身份。 identity.name 为空。看起来用户身份没有传递到 Signalr 中心。
您在 API 中没有获得用户身份,因为您是作为应用程序而不是用户对其进行身份验证。
仅获取资源和 ClientCredentials 的 acquireTokenAsync 重载用于客户端凭据流(a.k.a 仅限应用程序流)。
您需要做的是使用 On-behalf-of 流程将您为 API1 获得的令牌交换为 API2.
的令牌所以在 API1 的 Startup.Auth,TokenValidation 参数中,将 Save SigninToken 设置为 true,如下所示:
app.UseOpenIdConnectAuthentication(
OpenIdConnectAuthenticationOptions
{
// ...
TokenValidationParameters = new TokenValidationParameters
{
SaveSigninToken = true
},
// ...
});
然后无论你想在哪里调用你的 API2,请执行以下操作:
ClientCredential clientCred = new ClientCredential(clientId, appKey);
var bootstrapContext = ClaimsPrincipal.Current.Identities.First().BootstrapContext as System.IdentityModel.Tokens.BootstrapContext;
string userName = ClaimsPrincipal.Current.FindFirst(ClaimTypes.Upn) != null ? ClaimsPrincipal.Current.FindFirst(ClaimTypes.Upn).Value : ClaimsPrincipal.Current.FindFirst(ClaimTypes.Email).Value;
string userAccessToken = bootstrapContext.Token;
UserAssertion userAssertion = new UserAssertion(bootstrapContext.Token, "urn:ietf:params:oauth:grant-type:jwt-bearer", userName);
result = await authContext.AcquireTokenAsync(api2ResourceId, clientCred, userAssertion);
在示例中查看:https://github.com/Azure-Samples/active-directory-dotnet-webapi-onbehalfof,特别是 ToDoService 的 Startup.Auth.cs 和 TodoListController.cs.
注意:此示例适用于本机应用程序 + 网络 api,您正在将其调整为网络应用程序 + 网络 api.
Edit - 通过在 JS acquireToken 调用中指定 API1 来确保您的 JS 代码正在为您的 API1 请求令牌,如下所示:
var authContext = new AuthenticationContext({
tenant: tenantId,
clientId: jsclientId,
postLogoutRedirectUri: window.location.origin,
cacheLocation: 'localStorage',
endpoints: {
api1Url: api1ResourceUri
}
});
authContext.acquireToken(api1clientId, function (error, token) {
if (error || !token) {
authContext.clearCache();
authContext.login();
}
});