Microsoft.Identity.Web 添加了扩展方法,这些方法为调用 Microsoft Graph 或下游 Web API 提供便利服务。 若要详细了解这些方法,请参阅调用 Web API 的 Web 应用:调用 API。 使用这些帮助程序方法,你无需手动获取令牌。
但是,如果你确实想要手动获取令牌,可以通过以下代码以示例方式了解如何使用 Microsoft.Identity.Web 在主控制器中执行此操作。 它使用 REST API(而不是 Microsoft Graph SDK)调用 Microsoft Graph。 通常,无需获取令牌,而是需要生成添加到请求的授权标头。 若要获取授权标头,请通过依赖项注入将 IAuthorizationHeaderProvider
服务注入的构造函数控制器(如果使用 Blazor,则注入页面构造函数),并在控制器操作中使用它。 此接口提供了方法来生成包含协议(持有者、Pop 等)和一个令牌的字符串。 若要获取授权标头来代表用户调用 API,请使用 (CreateAuthorizationHeaderForUserAsync
)。 若要获取授权标头来代表应用程序本身调用下游 API,请在守护程序方案中使用 (CreateAuthorizationHeaderForAppAsync
)。
控制器方法受 [Authorize]
属性的保护,该属性确保只有经过身份验证的调用可使用 Web API。
[Authorize]
public class MyApiController : Controller
{
/// <summary>
/// The web API will accept only tokens 1) for users, 2) that have the `access_as_user` scope for
/// this API.
/// </summary>
static readonly string[] scopeRequiredByApi = new string[] { "access_as_user" };
static readonly string[] scopesToAccessDownstreamApi = new string[] { "api://MyTodolistService/access_as_user" };
readonly IAuthorizationHeaderProvider authorizationHeaderProvider;
public MyApiController(IAuthorizationHeaderProvider authorizationHeaderProvider)
{
this.authorizationHeaderProvider = authorizationHeaderProvider;
}
[RequiredScopes(Scopes = scopesToAccessDownstreamApi)]
public IActionResult Index()
{
// Get an authorization header.
IAuthorizationHeaderProvider authorizationHeaderProvider = this.GetAuthorizationHeaderProvider();
string[] scopes = new string[]{"user.read"};
string authorizationHeader = await authorizationHeaderProvider.CreateAuthorizationHeaderForUserAsync(scopes);
return await callTodoListService(authorizationHeader);
}
}
若要了解关于 callTodoListService
方法的详细信息,请参阅用于调用 Web API 的 Web API:调用 API。
适用于 ASP.NET 的代码类似于为 ASP.NET Core 显示的代码:
- 受 [Authorize] 属性保护的控制器操作会提取控制器的
ClaimsPrincipal
成员的租户 ID 和用户 ID。 (ASP.NET 使用 HttpContext.User
。)Microsoft.Identity.Web.OWIN 将扩展方法添加到控制器,从而提供便捷的服务来调用 Microsoft Graph 或下游 Web API,或者获取授权标头甚至令牌。 若要详细了解用于直接调用 API 的方法,请参阅调用 Web API 的 Web 应用:调用 API。 使用这些帮助程序方法,你无需手动获取令牌。
但是,如果你确实想要手动获取令牌或生成授权标头,可查看以下代码了解如何使用 Microsoft.Identity.Web 在控制器中执行此操作。 它使用 REST API 而不是 Microsoft Graph SDK 来调用 API (Microsoft Graph)。
若要获取授权标头,请使用扩展方法 GetAuthorizationHeaderProvider
从控制器获取 IAuthorizationHeaderProvider
服务。 若要获取授权标头来代表用户调用 API,请使用 (CreateAuthorizationHeaderForUserAsync
)。 若要获取授权标头来代表应用程序本身调用下游 API,请在守护程序方案中使用 (CreateAuthorizationHeaderForAppAsync
)。
控制器方法受 [Authorize]
属性的保护,该属性确保只有经过身份验证的用户可使用 Web 应用。
下面的代码片段显示了 HomeController
的操作,该操作获取一个授权标头来将 Microsoft Graph 作为 REST API 进行调用:
[Authorize]
public class MyApiController : Controller
{
[AuthorizeForScopes(Scopes = new[] { "user.read" })]
public async Task<IActionResult> Profile()
{
// Get an authorization header.
IAuthorizationHeaderProvider authorizationHeaderProvider = this.GetAuthorizationHeaderProvider();
string[] scopes = new string[]{"user.read"};
string authorizationHeader = await authorizationHeaderProvider.CreateAuthorizationHeaderForUserAsync(scopes);
// Use the access token to call a protected web API.
HttpClient client = new HttpClient();
client.DefaultRequestHeaders.Add("Authorization", authorizationHeader);
string json = await client.GetStringAsync(url);
}
}
下面的代码片段显示了 MyApiController
的操作,该操作获取一个访问令牌来将 Microsoft Graph 作为 REST API 进行调用:
[Authorize]
public class HomeController : Controller
{
[AuthorizeForScopes(Scopes = new[] { "user.read" })]
public async Task<IActionResult> Profile()
{
// Get an authorization header.
ITokenAcquirer tokenAcquirer = TokenAcquirerFactory.GetDefaultInstance().GetTokenAcquirer();
string[] scopes = new string[]{"user.read"};
string token = await await tokenAcquirer.GetTokenForUserAsync(scopes);
// Use the access token to call a protected web API.
HttpClient client = new HttpClient();
client.DefaultRequestHeaders.Add("Authorization", $"Bearer {token}");
string json = await client.GetStringAsync(url);
}
}
下面是在 API 控制器的操作中调用的代码示例。 它调用下游 API - Microsoft Graph。
@RestController
public class ApiController {
@Autowired
MsalAuthHelper msalAuthHelper;
@RequestMapping("/graphMeApi")
public String graphMeApi() throws MalformedURLException {
String oboAccessToken = msalAuthHelper.getOboToken("https://graph.microsoft.com/.default");
return callMicrosoftGraphMeEndpoint(oboAccessToken);
}
}
Python Web API 需要借助中间件来验证从客户端接收的持有者令牌。 然后,Web API 可通过调用 acquire_token_on_behalf_of
方法,使用 MSAL Python 库获取下游 API 的访问令牌。
下面是使用 acquire_token_on_behalf_of
方法和 Flask 框架获取访问令牌的代码示例。 它调用下游 API - Azure 管理订阅终结点。
def get(self):
_scopes = ["https://management.azure.com/user_impersonation"]
_azure_management_subscriptions_uri = "https://management.azure.com/subscriptions?api-version=2020-01-01"
current_access_token = request.headers.get("Authorization", None)
#This example only uses the default memory token cache and should not be used for production
msal_client = msal.ConfidentialClientApplication(
client_id=os.environ.get("CLIENT_ID"),
authority=os.environ.get("AUTHORITY"),
client_credential=os.environ.get("CLIENT_SECRET"))
#acquire token on behalf of the user that called this API
arm_resource_access_token = msal_client.acquire_token_on_behalf_of(
user_assertion=current_access_token.split(' ')[1],
scopes=_scopes
)
headers = {'Authorization': arm_resource_access_token['token_type'] + ' ' + arm_resource_access_token['access_token']}
subscriptions_list = req.get(_azure_management_subscriptions_uri), headers=headers).json()
return jsonify(subscriptions_list)
(高级)从后台应用、API 和服务访问已登录用户的令牌缓存
你可以使用 MSAL 的令牌缓存实现来允许后台应用、API 和服务使用访问令牌缓存,以便在用户不在时代表用户继续执行操作。 如果后台应用和服务需要在用户退出前端 Web 应用后继续代表用户工作,则这样做特别有用。
如今,大多数后台进程都在需要使用用户的数据时使用应用程序权限,而无需用户在场进行身份验证或重新进行身份验证。 由于应用程序权限通常需要管理员同意,这需要特权提升,因此会遇到不必要的摩擦,因为开发人员不打算获得针对其应用的、超出用户最初同意的权限的权限。
GitHub 上的此代码示例演示了如何通过从后台应用访问 MSAL 的令牌缓存来避免这种不必要的摩擦:
从后台应用、API 和服务访问已登录用户的令牌缓存