我能否将颁发给一个应用程序的令牌用于 Azure AD SSO 中的另一个应用程序?
Can I use a token issued to one application with another application in Azure AD SSO?
假设我在 Azure AD 中配置了两个 'applications'。一个是名为 'A' 的 Web API,另一个是名为 'B' 的本机 windows 应用程序。用户从 Windows 商店下载 'B' 并使用他们的 Office 365 凭据登录到 Azure AD。效果很好。他们得到一个代币。
我可以使用该令牌并将其附加到对 API 应用程序 'A' 的 REST API 调用吗?
编辑:所以我已经取得了一些进步。我能够获得 Web 令牌 API,但我仍然获得 'unauthorized',并且它目前正在为我提供交互式登录以获取 Web 令牌 API。
这里是关于我的配置的更多细节:
- Azure AD 租户
- 'Foo App for UWP'
- 应用程序类型:本机客户端应用程序
- 客户端 ID:{123}
- 重定向 URI:ms-appx-web://Microsoft.AAD.BrokerPlugin/S-1-15-2-999
- 对其他应用程序的权限:
- 'FooAPI':委派权限:'Access MyCompany.Foo.Api'
- 'Foo Web API'
- 应用程序类型:Web 应用程序
- 登录URL:https://api.foo.com
- 客户端 ID:{456}
- 应用 ID URI:https://api.foo.com
- 回复URL:https://api.foo.com/.auth/login/aad/callback
- Azure API 应用程序
- api-foo-us-east.azurewebsites.net
- 自定义域:api.foo.com
- 使用 *.foo.com 通配符证书启用 SSL 绑定
- 应用服务身份验证
- 开启
- 使用 Azure Active Directory 登录
- 高级
- 客户端 ID:{456}
- 发行人Url:https://sts.windows.net/{tenant_id}/
- api-foo-us-west.azurewebsites.net
- 自定义域:api.foo.com
- 使用 *.foo.com 通配符证书启用 SSL 绑定
- 应用服务身份验证
- 开启
- 使用 Azure Active Directory 登录
- 高级
- 客户端 ID:{456}
- 发行人Url:https://sts.windows.net/{tenant_id}/
- api-foo-asia-southeast.azurewebsites.net
- 自定义域:api.foo.com
- 使用 *.foo.com 通配符证书启用 SSL 绑定
- 应用服务身份验证
- 开启
- 使用 Azure Active Directory 登录
- 高级
- 客户端 ID:{456}
- 发行人Url:https://sts.windows.net/{tenant_id}/
现在是代码。
当我验证我的 UWP 应用程序时,我是这样做的:
static string clientId = "{123}";
static string authority = "https://login.windows.net/{tenant_id}";
static string uri = string.Format("ms-appx-web://Microsoft.AAD.BrokerPlugin/{0}", WebAuthenticationBroker.GetCurrentApplicationCallbackUri().Host.ToUpper());
private AuthenticationContext authContext = new AuthenticationContext(authority);
private async void AttemptLogin()
{
WebAccountProvider wap = await WebAuthenticationCoreManager.FindAccountProviderAsync("https://login.microsoft.com", authority);
WebTokenRequest wtr = new WebTokenRequest(wap, string.Empty, clientId);
wtr.Properties.Add("resource", "https://graph.windows.net");
// there is no recorded user. let's start a sign in flow without imposing a specific account.
WebTokenRequestResult wtrr = await WebAuthenticationCoreManager.RequestTokenAsync(wtr);
if (wtrr.ResponseStatus == WebTokenRequestStatus.Success)
{
userAccount = wtrr.ResponseData[0].WebAccount;
token = wtrr.ResponseData[0].Token;
}
if (userAccount != null)
{
OnUserSignedIn();
}
else
{
// we got bigger fish to fry!
}
}
private void OnUserSignedIn()
{
var redirectUri = new Uri(uri);
AuthenticationResult authResult = await authContext.AcquireTokenAsync("https://api.foo.com", clientId, redirectUri);
// just some junk code to call the Web API
var accountId = ApiClientHelper.AccountIdentifier;
var client = ApiClientHelper.GetClient();
client.HttpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(authResult.AccessTokenType, authResult.AccessToken);
try
{
var allCustomers = await client.Customers.GetAllWithOperationResponseAsync(accountId);
}
catch (Exception ex)
{
Debug.WriteLine(ex.ToString());
}
}
所以有趣的是,当我在 AttemptLogin 方法中获取“https://graph.windows.net”的令牌时,以及当我获取“https://api.foo.com' 令牌字符串值是相同的。
我返回的状态码是'Unauthorized'。
如果你是原生app,就没有"logging in"这样的东西。您执行的操作是 always 为某些资源请求令牌。在获取此类令牌的过程中,最终用户可能必须执行登录 - 但从应用程序的角度来看,该操作是获取令牌。
因此:如果在您的令牌获取操作中您为您的 API 请求令牌,您将让用户完成登录手势并且您将获得您的 API 的令牌。
即使您最初获得了不同 API 的令牌 - 您与第一个访问令牌一起获得的刷新令牌也能够为您的本机客户端注册的所有 API 获取访问令牌请求访问权限,因此您无需任何额外的用户交互即可为您的 API 获取新令牌。
我明白了为什么它不起作用。首先,我通过 Azure 门户使用身份验证,而不是在我的应用程序中设置 owin。其次,我错过了一个非常关键但不容易知道哪里出了问题的关键 nuget 包。要执行 startup.cs 代码,需要 Microsoft.owin.host.systemweb。没有它,您只会收到未经授权的消息,而没有其他解释。
假设我在 Azure AD 中配置了两个 'applications'。一个是名为 'A' 的 Web API,另一个是名为 'B' 的本机 windows 应用程序。用户从 Windows 商店下载 'B' 并使用他们的 Office 365 凭据登录到 Azure AD。效果很好。他们得到一个代币。
我可以使用该令牌并将其附加到对 API 应用程序 'A' 的 REST API 调用吗?
编辑:所以我已经取得了一些进步。我能够获得 Web 令牌 API,但我仍然获得 'unauthorized',并且它目前正在为我提供交互式登录以获取 Web 令牌 API。
这里是关于我的配置的更多细节:
- Azure AD 租户
- 'Foo App for UWP'
- 应用程序类型:本机客户端应用程序
- 客户端 ID:{123}
- 重定向 URI:ms-appx-web://Microsoft.AAD.BrokerPlugin/S-1-15-2-999
- 对其他应用程序的权限:
- 'FooAPI':委派权限:'Access MyCompany.Foo.Api'
- 'Foo Web API'
- 应用程序类型:Web 应用程序
- 登录URL:https://api.foo.com
- 客户端 ID:{456}
- 应用 ID URI:https://api.foo.com
- 回复URL:https://api.foo.com/.auth/login/aad/callback
- 'Foo App for UWP'
- Azure API 应用程序
- api-foo-us-east.azurewebsites.net
- 自定义域:api.foo.com
- 使用 *.foo.com 通配符证书启用 SSL 绑定
- 应用服务身份验证
- 开启
- 使用 Azure Active Directory 登录
- 高级
- 客户端 ID:{456}
- 发行人Url:https://sts.windows.net/{tenant_id}/
- api-foo-us-west.azurewebsites.net
- 自定义域:api.foo.com
- 使用 *.foo.com 通配符证书启用 SSL 绑定
- 应用服务身份验证
- 开启
- 使用 Azure Active Directory 登录
- 高级
- 客户端 ID:{456}
- 发行人Url:https://sts.windows.net/{tenant_id}/
- api-foo-asia-southeast.azurewebsites.net
- 自定义域:api.foo.com
- 使用 *.foo.com 通配符证书启用 SSL 绑定
- 应用服务身份验证
- 开启
- 使用 Azure Active Directory 登录
- 高级
- 客户端 ID:{456}
- 发行人Url:https://sts.windows.net/{tenant_id}/
- api-foo-us-east.azurewebsites.net
现在是代码。
当我验证我的 UWP 应用程序时,我是这样做的:
static string clientId = "{123}";
static string authority = "https://login.windows.net/{tenant_id}";
static string uri = string.Format("ms-appx-web://Microsoft.AAD.BrokerPlugin/{0}", WebAuthenticationBroker.GetCurrentApplicationCallbackUri().Host.ToUpper());
private AuthenticationContext authContext = new AuthenticationContext(authority);
private async void AttemptLogin()
{
WebAccountProvider wap = await WebAuthenticationCoreManager.FindAccountProviderAsync("https://login.microsoft.com", authority);
WebTokenRequest wtr = new WebTokenRequest(wap, string.Empty, clientId);
wtr.Properties.Add("resource", "https://graph.windows.net");
// there is no recorded user. let's start a sign in flow without imposing a specific account.
WebTokenRequestResult wtrr = await WebAuthenticationCoreManager.RequestTokenAsync(wtr);
if (wtrr.ResponseStatus == WebTokenRequestStatus.Success)
{
userAccount = wtrr.ResponseData[0].WebAccount;
token = wtrr.ResponseData[0].Token;
}
if (userAccount != null)
{
OnUserSignedIn();
}
else
{
// we got bigger fish to fry!
}
}
private void OnUserSignedIn()
{
var redirectUri = new Uri(uri);
AuthenticationResult authResult = await authContext.AcquireTokenAsync("https://api.foo.com", clientId, redirectUri);
// just some junk code to call the Web API
var accountId = ApiClientHelper.AccountIdentifier;
var client = ApiClientHelper.GetClient();
client.HttpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(authResult.AccessTokenType, authResult.AccessToken);
try
{
var allCustomers = await client.Customers.GetAllWithOperationResponseAsync(accountId);
}
catch (Exception ex)
{
Debug.WriteLine(ex.ToString());
}
}
所以有趣的是,当我在 AttemptLogin 方法中获取“https://graph.windows.net”的令牌时,以及当我获取“https://api.foo.com' 令牌字符串值是相同的。
我返回的状态码是'Unauthorized'。
如果你是原生app,就没有"logging in"这样的东西。您执行的操作是 always 为某些资源请求令牌。在获取此类令牌的过程中,最终用户可能必须执行登录 - 但从应用程序的角度来看,该操作是获取令牌。 因此:如果在您的令牌获取操作中您为您的 API 请求令牌,您将让用户完成登录手势并且您将获得您的 API 的令牌。 即使您最初获得了不同 API 的令牌 - 您与第一个访问令牌一起获得的刷新令牌也能够为您的本机客户端注册的所有 API 获取访问令牌请求访问权限,因此您无需任何额外的用户交互即可为您的 API 获取新令牌。
我明白了为什么它不起作用。首先,我通过 Azure 门户使用身份验证,而不是在我的应用程序中设置 owin。其次,我错过了一个非常关键但不容易知道哪里出了问题的关键 nuget 包。要执行 startup.cs 代码,需要 Microsoft.owin.host.systemweb。没有它,您只会收到未经授权的消息,而没有其他解释。