受保護 Web API:驗證範圍和應用程式角色
本文說明如何在您的 Web API 中新增授權。 這項保護可確保 API 僅由下列項目呼叫:
- 代表具有適當範圍和角色之使用者的應用程式。
- 具有適當應用程式角色的精靈應用程式。
本文中的程式碼片段是從 GitHub 上的下列程式碼範例中擷取:
若要保護 ASP.NET 或 ASP.NET Core Web API,您必須將 [Authorize]
屬性新增至下列其中一個項目:
- 如果您希望所有控制器動作都受到保護,則為控制器本身
- 您 API 的個別控制器動作
[Authorize]
public class TodoListController : Controller
{
// ...
}
但此種保護並不足夠。 這只能保證 ASP.NET 和 ASP.NET Core 會驗證權杖。 您的 API 必須驗證用來呼叫 API 的權杖是否以預期的宣告進行要求。 下列宣告特別需要驗證:
- 如果代表使用者呼叫 API,則需驗證「範圍」。
- 如果可從精靈程式應用程式呼叫 API,則需驗證「應用程式角色」。
在代表使用者呼叫的 API 中驗證範圍
如果用戶端應用程式代表使用者呼叫您的 API,則 API 必須要求具有 API 特定範圍的持有人權杖。 如需詳細資訊,請參閱程式碼設 | 持有人權杖。
在 ASP.NET Core 中,您可以使用 Microsoft.Identity.Web 來驗證每個控制器動作中的範圍。 您也可以在控制器層級或整個應用程式中確認範圍。
確認每個控制器動作的範圍
您可以使用 [RequiredScope]
屬性來確認控制器動作中的範圍。 這個屬性有數個覆寫。 一個會直接採用所需的範圍,另一個則會採用設定的金鑰。
使用硬式編碼範圍確認控制器動作上的範圍
下列程式碼片段顯示硬式編碼範圍的 [RequiredScope]
屬性使用。
using Microsoft.Identity.Web
[Authorize]
public class TodoListController : Controller
{
/// <summary>
/// The web API will accept only tokens that have the `access_as_user` scope for
/// this API.
/// </summary>
const string scopeRequiredByApi = "access_as_user";
// GET: api/values
[HttpGet]
[RequiredScope(scopeRequiredByApi)]
public IEnumerable<TodoItem> Get()
{
// Do the work and return the result.
// ...
}
// ...
}
使用設定中定義的範圍確認控制器動作上的範圍
您也可以在設定中宣告這些必要的範圍,並參考設定金鑰:
比方說,在 appsettings.json 中,您有下列設定:
{
"AzureAd" : {
// more settings
"Scopes" : "access_as_user access_as_admin"
}
}
然後,在 [RequiredScope]
屬性中參考該設定:
using Microsoft.Identity.Web
[Authorize]
public class TodoListController : Controller
{
// GET: api/values
[HttpGet]
[RequiredScope(RequiredScopesConfigurationKey = "AzureAd:Scopes")]
public IEnumerable<TodoItem> Get()
{
// Do the work and return the result.
// ...
}
// ...
}
有條件地驗證範圍
在某些情況下,您會想要有條件地驗證範圍。 您可以使用 HttpContext
上的 VerifyUserHasAnyAcceptedScope
擴充方法。
using Microsoft.Identity.Web
[Authorize]
public class TodoListController : 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" };
// GET: api/values
[HttpGet]
public IEnumerable<TodoItem> Get()
{
HttpContext.VerifyUserHasAnyAcceptedScope(scopeRequiredByApi);
// Do the work and return the result.
// ...
}
// ...
}
確認控制器層級的範圍
您也可以確認整個控制器的範圍
使用硬式編碼範圍確認控制器上的範圍
下列程式碼片段顯示控制器上硬式編碼範圍的 [RequiredScope]
屬性使用方式。 若要使用 RequiredScopeAttribute,您必須:
- 在 Startup.cs 中使用
AddMicrosoftIdentityWebApi
,如 [程式代碼設定] 所示 - 否則,請將
ScopeAuthorizationRequirement
新增至授權原則,如授權原則中所述。
using Microsoft.Identity.Web
[Authorize]
[RequiredScope(scopeRequiredByApi)]
public class TodoListController : 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" };
// GET: api/values
[HttpGet]
public IEnumerable<TodoItem> Get()
{
// Do the work and return the result.
// ...
}
// ...
}
使用設定中定義的範圍確認控制器上的範圍
就像在動作中一樣,您也可以在設定中宣告這些必要的範圍,並參考設定金鑰:
using Microsoft.Identity.Web
[Authorize]
[RequiredScope(RequiredScopesConfigurationKey = "AzureAd:Scopes")]
public class TodoListController : Controller
{
// GET: api/values
[HttpGet]
public IEnumerable<TodoItem> Get()
{
// Do the work and return the result.
// ...
}
// ...
}
更全域地驗證範圍
建議的做法是為您的 Web API 定義精細的範圍,以及驗證每個控制器動作中的範圍。 不過,您也可以在應用程式或控制器層級驗證範圍。 如需詳細資訊,請參閱 ASP.NET Core 文件中的宣告型授權。
驗證了什麼?
[RequiredScope]
屬性和 VerifyUserHasAnyAcceptedScope
方法會執行類似下列步驟的動作:
- 確認有名為
http://schemas.microsoft.com/identity/claims/scope
或scp
的宣告。 - 確認宣告的值包含 API 所預期的範圍。
在精靈應用程式所呼叫的 API 中驗證應用程式角色
如果您的 Web API 是由精靈應用程式呼叫,該應用程式應該需要 Web API 的應用程式權限。 如公開應用程式權限 (應用程式角色) 所示,您的 API 會公開這類權限。 其中一個範例是 access_as_application
應用程式角色。
您現在必須讓 API 確認其所收到的權杖包含 roles
宣告,而且此宣告具有預期的值。 除了控制器動作會測試角色而非範圍以外,驗證碼類似於可驗證委派權限的程式碼:
下列程式碼片段顯示如何驗證應用程式角色;
using Microsoft.Identity.Web
[Authorize]
public class TodoListController : ApiController
{
public IEnumerable<TodoItem> Get()
{
HttpContext.ValidateAppRole("access_as_application");
// ...
}
不過您也可以使用控制器上的 [Authorize(Roles = "access_as_application")]
屬性或動作 (或 Razor 頁面)。
[Authorize(Roles = "access_as_application")]
MyController : ApiController
{
// ...
}
ASP.NET Core 中以角色為基礎的授權會列出數種實作角色型授權的方法。 開發人員可以選擇其中一個適合各其案例的方法。
如需實用的範例,請參閱依角色和群組授權的 Web 應用程式漸進式教學課程。
在代表使用者呼叫的 API 中驗證應用程式角色
使用者也可以使用使用者指派模式中的角色宣告,詳情請參閱如何在您的應用程式中新增應用程式角色,並且在權杖中接收這些角色。 如果角色可指派給兩者,檢查角色將可讓應用程式以使用者身分登入,以及讓使用者以應用程式身分登入。 我們建議您為使用者和應用程式宣告不同的角色,以避免發生混淆。
如果您已定義具有使用者/群組的應用程式角色,則角色宣告也可以在 API 和範圍中進行驗證。 此案例中應用程式角色的驗證邏輯與精靈應用程式呼叫 API 相同,因為使用者/群組和應用程式的角色宣告沒有差異。
如果只能由精靈應用程式呼叫 Web API,則接受僅限應用程式權杖
如果您只希望精靈應用程式呼叫您的 Web API,請在驗證應用程式角色時,新增權杖為僅限應用程式權杖這個條件。
string oid = ClaimsPrincipal.Current.FindFirst("oid")?.Value;
string sub = ClaimsPrincipal.Current.FindFirst("sub")?.Value;
bool isAppOnly = oid != null && sub != null && oid == sub;
檢查反向條件,只能允許以使用者身分登入的應用程式呼叫您的 API。
使用以 ACL 為基礎的授權
除了以應用程式角色為基礎的授權,您也可以使用以存取控制清單 (ACL) 為基礎的授權模式來控制沒有 roles
宣告的權杖,藉此保護您的 Web API。
如果您在 ASP.NET Core 上使用 Microsoft.Identity.Web
,則必須宣告您使用以 ACL 為基礎的授權,否則在提供的宣告中沒有角色或範圍時,Microsoft Identity Web 將會擲回例外狀況:
System.UnauthorizedAccessException: IDW10201: Neither scope or roles claim was found in the bearer token.
若要避免這個例外狀況,請在 appsettings.json 中或以程式設計的方式將 AllowWebApiToBeAuthorizedByACL
設定屬性設定為 true
。
{
"AzureAD"
{
// other properties
"AllowWebApiToBeAuthorizedByACL" : true,
// other properties
}
}
如果您將 AllowWebApiToBeAuthorizedByACL
設為 true
,您必須負責確保 ACL 機制。
下一步
若要深入了解,請在下列多部分教學課程系列中建置可登入使用者的 ASP.NET Core Web 應用程式
探索 Microsoft 身分識別平台 Web API 範例