ASP.NET Core 中的資源型授權
授權方法取決於資源。 例如,只有文件的作者有權更新文件。 因此,必須先從資料存放區擷取文件,才能進行授權評估。
屬性評估會在資料繫結之前,以及在載入文件的頁面處理常式或動作之前發生。 基於這些原因,具有 [Authorize]
屬性的宣告式授權會不足。 相反地,您可以叫用自訂授權方法,也就是稱為命令式授權的樣式。
檢視或下載範例程式碼 (如何下載)。
使用受授權保護的使用者資料建立 ASP.NET Core 應用程式,其中包含使用資源型授權的範例應用程式。
使用命令式授權
授權會實作為 IAuthorizationService 服務,並在應用程式啟動的服務集合中註冊。 該服務透過對頁面處理常式或動作的相依性插入來提供。
public class DocumentController : Controller
{
private readonly IAuthorizationService _authorizationService;
private readonly IDocumentRepository _documentRepository;
public DocumentController(IAuthorizationService authorizationService,
IDocumentRepository documentRepository)
{
_authorizationService = authorizationService;
_documentRepository = documentRepository;
}
IAuthorizationService
有兩個 AuthorizeAsync
方法來多載:一個接受資源和原則名稱,另一個接受資源和要評估的需求清單。
Task<AuthorizationResult> AuthorizeAsync(ClaimsPrincipal user,
object resource,
IEnumerable<IAuthorizationRequirement> requirements);
Task<AuthorizationResult> AuthorizeAsync(ClaimsPrincipal user,
object resource,
string policyName);
在下列範例中,要保護的資源會載入至自訂 Document
物件。 叫用 AuthorizeAsync
多載,以判斷是否允許目前使用者編輯提供的文件。 自訂的「EditPolicy」授權原則會納入決策中。 如需建立授權原則的詳細資訊,請參閱自訂原則型授權。
注意
下列程式碼範例假設驗證已執行並設定 User
屬性。
public async Task<IActionResult> OnGetAsync(Guid documentId)
{
Document = _documentRepository.Find(documentId);
if (Document == null)
{
return new NotFoundResult();
}
var authorizationResult = await _authorizationService
.AuthorizeAsync(User, Document, "EditPolicy");
if (authorizationResult.Succeeded)
{
return Page();
}
else if (User.Identity.IsAuthenticated)
{
return new ForbidResult();
}
else
{
return new ChallengeResult();
}
}
撰寫資源型處理常式
撰寫資源型授權的處理常式與撰寫一般需求處理常式並無太大不同。 建立自訂需求類別,並實作需求處理常式類別。 如需建立需求類別的詳細資訊,請參閱需求。
處理常式類別會同時指定需求和資源類型。 例如,使用 SameAuthorRequirement
和 Document
資源的處理常式如下:
public class DocumentAuthorizationHandler :
AuthorizationHandler<SameAuthorRequirement, Document>
{
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context,
SameAuthorRequirement requirement,
Document resource)
{
if (context.User.Identity?.Name == resource.Author)
{
context.Succeed(requirement);
}
return Task.CompletedTask;
}
}
public class SameAuthorRequirement : IAuthorizationRequirement { }
在上述範例中,假設 SameAuthorRequirement
是更泛型 SpecificAuthorRequirement
類別的特殊案例。 類別 SpecificAuthorRequirement
(未顯示) 包含代表作者名稱的 Name
屬性。 屬性 Name
可以設定為目前的使用者。
在 Program.cs
中註冊需求和處理常式:
builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();
builder.Services.AddAuthorization(options =>
{
options.AddPolicy("EditPolicy", policy =>
policy.Requirements.Add(new SameAuthorRequirement()));
});
builder.Services.AddSingleton<IAuthorizationHandler, DocumentAuthorizationHandler>();
builder.Services.AddSingleton<IAuthorizationHandler, DocumentAuthorizationCrudHandler>();
builder.Services.AddScoped<IDocumentRepository, DocumentRepository>();
作業需求
如果您要根據 CRUD 的結果做出決策 (建立、讀取、更新、刪除) 作業,請使用 OperationAuthorizationRequirement 協助程式類別。 此類別可讓您撰寫單一處理程式,而不是每個作業類型的個別類別。 若要使用它,請提供一些作業名稱:
public static class Operations
{
public static OperationAuthorizationRequirement Create =
new OperationAuthorizationRequirement { Name = nameof(Create) };
public static OperationAuthorizationRequirement Read =
new OperationAuthorizationRequirement { Name = nameof(Read) };
public static OperationAuthorizationRequirement Update =
new OperationAuthorizationRequirement { Name = nameof(Update) };
public static OperationAuthorizationRequirement Delete =
new OperationAuthorizationRequirement { Name = nameof(Delete) };
}
處理常式實作方式如下,使用 OperationAuthorizationRequirement
需求和資源 Document
:
public class DocumentAuthorizationCrudHandler :
AuthorizationHandler<OperationAuthorizationRequirement, Document>
{
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context,
OperationAuthorizationRequirement requirement,
Document resource)
{
if (context.User.Identity?.Name == resource.Author &&
requirement.Name == Operations.Read.Name)
{
context.Succeed(requirement);
}
return Task.CompletedTask;
}
}
上述處理常式會使用資源、使用者的 identity 和需求的 Name
屬性來驗證作業。
操作資源處理常式的挑戰與禁止
本節說明如何處理挑戰和禁止動作結果,以及挑戰和禁止有何差異。
如要呼叫作業性資源處理常式,請在頁面處理常式或動作中叫用 AuthorizeAsync
時指定作業。 下列範例會判斷是否允許已驗證的使用者檢視所提供的文件。
注意
下列程式碼範例假設驗證已執行並設定 User
屬性。
public async Task<IActionResult> OnGetAsync(Guid documentId)
{
Document = _documentRepository.Find(documentId);
if (Document == null)
{
return new NotFoundResult();
}
var authorizationResult = await _authorizationService
.AuthorizeAsync(User, Document, Operations.Read);
if (authorizationResult.Succeeded)
{
return Page();
}
else if (User.Identity.IsAuthenticated)
{
return new ForbidResult();
}
else
{
return new ChallengeResult();
}
}
如果授權成功,則會傳回檢視文件的頁面。 如果授權失敗,但使用者有經過驗證,則傳回 ForbidResult
會通知任何驗證中介軟體授權失敗。 必須執行驗證時,會傳回 ChallengeResult
。 針對互動式瀏覽器用戶端,將使用者重新導向至登入頁面可能較適合。
授權方法取決於資源。 例如,只有文件的作者有權更新文件。 因此,必須先從資料存放區擷取文件,才能進行授權評估。
屬性評估會在資料繫結之前,以及在載入文件的頁面處理常式或動作之前發生。 基於這些原因,具有 [Authorize]
屬性的宣告式授權會不足。 相反地,您可以叫用自訂授權方法,也就是稱為命令式授權的樣式。
檢視或下載範例程式碼 (如何下載)。
使用受授權保護的使用者資料建立 ASP.NET Core 應用程式,其中包含使用資源型授權的範例應用程式。
使用命令式授權
授權會實作為 IAuthorizationService 服務,並在 Startup
類別內的服務集合中註冊。 該服務透過對頁面處理常式或動作的相依性插入來提供。
public class DocumentController : Controller
{
private readonly IAuthorizationService _authorizationService;
private readonly IDocumentRepository _documentRepository;
public DocumentController(IAuthorizationService authorizationService,
IDocumentRepository documentRepository)
{
_authorizationService = authorizationService;
_documentRepository = documentRepository;
}
IAuthorizationService
有兩個 AuthorizeAsync
方法來多載:一個接受資源和原則名稱,另一個接受資源和要評估的需求清單。
Task<AuthorizationResult> AuthorizeAsync(ClaimsPrincipal user,
object resource,
IEnumerable<IAuthorizationRequirement> requirements);
Task<AuthorizationResult> AuthorizeAsync(ClaimsPrincipal user,
object resource,
string policyName);
在下列範例中,要保護的資源會載入至自訂 Document
物件。 叫用 AuthorizeAsync
多載,以判斷是否允許目前使用者編輯提供的文件。 自訂的「EditPolicy」授權原則會納入決策中。 如需建立授權原則的詳細資訊,請參閱自訂原則型授權。
注意
下列程式碼範例假設驗證已執行並設定 User
屬性。
public async Task<IActionResult> OnGetAsync(Guid documentId)
{
Document = _documentRepository.Find(documentId);
if (Document == null)
{
return new NotFoundResult();
}
var authorizationResult = await _authorizationService
.AuthorizeAsync(User, Document, "EditPolicy");
if (authorizationResult.Succeeded)
{
return Page();
}
else if (User.Identity.IsAuthenticated)
{
return new ForbidResult();
}
else
{
return new ChallengeResult();
}
}
撰寫資源型處理常式
撰寫資源型授權的處理常式與撰寫一般需求處理常式並無太大不同。 建立自訂需求類別,並實作需求處理常式類別。 如需建立需求類別的詳細資訊,請參閱需求。
處理常式類別會同時指定需求和資源類型。 例如,使用 SameAuthorRequirement
和 Document
資源的處理常式如下:
public class DocumentAuthorizationHandler :
AuthorizationHandler<SameAuthorRequirement, Document>
{
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context,
SameAuthorRequirement requirement,
Document resource)
{
if (context.User.Identity?.Name == resource.Author)
{
context.Succeed(requirement);
}
return Task.CompletedTask;
}
}
public class SameAuthorRequirement : IAuthorizationRequirement { }
在上述範例中,假設 SameAuthorRequirement
是更泛型 SpecificAuthorRequirement
類別的特殊案例。 類別 SpecificAuthorRequirement
(未顯示) 包含代表作者名稱的 Name
屬性。 屬性 Name
可以設定為目前的使用者。
在 Startup.ConfigureServices
中註冊需求和處理常式:
services.AddControllersWithViews();
services.AddRazorPages();
services.AddAuthorization(options =>
{
options.AddPolicy("EditPolicy", policy =>
policy.Requirements.Add(new SameAuthorRequirement()));
});
services.AddSingleton<IAuthorizationHandler, DocumentAuthorizationHandler>();
services.AddSingleton<IAuthorizationHandler, DocumentAuthorizationCrudHandler>();
services.AddScoped<IDocumentRepository, DocumentRepository>();
作業需求
如果您要根據 CRUD 的結果做出決策 (建立、讀取、更新、刪除) 作業,請使用 OperationAuthorizationRequirement 協助程式類別。 此類別可讓您撰寫單一處理程式,而不是每個作業類型的個別類別。 若要使用它,請提供一些作業名稱:
public static class Operations
{
public static OperationAuthorizationRequirement Create =
new OperationAuthorizationRequirement { Name = nameof(Create) };
public static OperationAuthorizationRequirement Read =
new OperationAuthorizationRequirement { Name = nameof(Read) };
public static OperationAuthorizationRequirement Update =
new OperationAuthorizationRequirement { Name = nameof(Update) };
public static OperationAuthorizationRequirement Delete =
new OperationAuthorizationRequirement { Name = nameof(Delete) };
}
處理常式實作方式如下,使用 OperationAuthorizationRequirement
需求和資源 Document
:
public class DocumentAuthorizationCrudHandler :
AuthorizationHandler<OperationAuthorizationRequirement, Document>
{
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context,
OperationAuthorizationRequirement requirement,
Document resource)
{
if (context.User.Identity?.Name == resource.Author &&
requirement.Name == Operations.Read.Name)
{
context.Succeed(requirement);
}
return Task.CompletedTask;
}
}
上述處理常式會使用資源、使用者的 identity 和需求的 Name
屬性來驗證作業。
操作資源處理常式的挑戰與禁止
本節說明如何處理挑戰和禁止動作結果,以及挑戰和禁止有何差異。
如要呼叫作業性資源處理常式,請在頁面處理常式或動作中叫用 AuthorizeAsync
時指定作業。 下列範例會判斷是否允許已驗證的使用者檢視所提供的文件。
注意
下列程式碼範例假設驗證已執行並設定 User
屬性。
public async Task<IActionResult> OnGetAsync(Guid documentId)
{
Document = _documentRepository.Find(documentId);
if (Document == null)
{
return new NotFoundResult();
}
var authorizationResult = await _authorizationService
.AuthorizeAsync(User, Document, Operations.Read);
if (authorizationResult.Succeeded)
{
return Page();
}
else if (User.Identity.IsAuthenticated)
{
return new ForbidResult();
}
else
{
return new ChallengeResult();
}
}
如果授權成功,則會傳回檢視文件的頁面。 如果授權失敗,但使用者有經過驗證,則傳回 ForbidResult
會通知任何驗證中介軟體授權失敗。 必須執行驗證時,會傳回 ChallengeResult
。 針對互動式瀏覽器用戶端,將使用者重新導向至登入頁面可能較適合。
授權方法取決於資源。 例如,只有文件的作者有權更新文件。 因此,必須先從資料存放區擷取文件,才能進行授權評估。
屬性評估會在資料繫結之前,以及在載入文件的頁面處理常式或動作之前發生。 基於這些原因,具有 [Authorize]
屬性的宣告式授權會不足。 相反地,您可以叫用自訂授權方法,也就是稱為命令式授權的樣式。
檢視或下載範例程式碼 (如何下載)。
使用受授權保護的使用者資料建立 ASP.NET Core 應用程式,其中包含使用資源型授權的範例應用程式。
使用命令式授權
授權會實作為 IAuthorizationService 服務,並在 Startup
類別內的服務集合中註冊。 該服務透過對頁面處理常式或動作的相依性插入來提供。
public class DocumentController : Controller
{
private readonly IAuthorizationService _authorizationService;
private readonly IDocumentRepository _documentRepository;
public DocumentController(IAuthorizationService authorizationService,
IDocumentRepository documentRepository)
{
_authorizationService = authorizationService;
_documentRepository = documentRepository;
}
IAuthorizationService
有兩個 AuthorizeAsync
方法來多載:一個接受資源和原則名稱,另一個接受資源和要評估的需求清單。
Task<AuthorizationResult> AuthorizeAsync(ClaimsPrincipal user,
object resource,
IEnumerable<IAuthorizationRequirement> requirements);
Task<AuthorizationResult> AuthorizeAsync(ClaimsPrincipal user,
object resource,
string policyName);
在下列範例中,要保護的資源會載入至自訂 Document
物件。 叫用 AuthorizeAsync
多載,以判斷是否允許目前使用者編輯提供的文件。 自訂的「EditPolicy」授權原則會納入決策中。 如需建立授權原則的詳細資訊,請參閱自訂原則型授權。
注意
下列程式碼範例假設驗證已執行並設定 User
屬性。
public async Task<IActionResult> OnGetAsync(Guid documentId)
{
Document = _documentRepository.Find(documentId);
if (Document == null)
{
return new NotFoundResult();
}
var authorizationResult = await _authorizationService
.AuthorizeAsync(User, Document, "EditPolicy");
if (authorizationResult.Succeeded)
{
return Page();
}
else if (User.Identity.IsAuthenticated)
{
return new ForbidResult();
}
else
{
return new ChallengeResult();
}
}
撰寫資源型處理常式
撰寫資源型授權的處理常式與撰寫一般需求處理常式並無太大不同。 建立自訂需求類別,並實作需求處理常式類別。 如需建立需求類別的詳細資訊,請參閱需求。
處理常式類別會同時指定需求和資源類型。 例如,使用 SameAuthorRequirement
和 Document
資源的處理常式如下:
public class DocumentAuthorizationHandler :
AuthorizationHandler<SameAuthorRequirement, Document>
{
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context,
SameAuthorRequirement requirement,
Document resource)
{
if (context.User.Identity?.Name == resource.Author)
{
context.Succeed(requirement);
}
return Task.CompletedTask;
}
}
public class SameAuthorRequirement : IAuthorizationRequirement { }
在上述範例中,假設 SameAuthorRequirement
是更泛型 SpecificAuthorRequirement
類別的特殊案例。 類別 SpecificAuthorRequirement
(未顯示) 包含代表作者名稱的 Name
屬性。 屬性 Name
可以設定為目前的使用者。
在 Startup.ConfigureServices
中註冊需求和處理常式:
services.AddMvc();
services.AddAuthorization(options =>
{
options.AddPolicy("EditPolicy", policy =>
policy.Requirements.Add(new SameAuthorRequirement()));
});
services.AddSingleton<IAuthorizationHandler, DocumentAuthorizationHandler>();
services.AddSingleton<IAuthorizationHandler, DocumentAuthorizationCrudHandler>();
services.AddScoped<IDocumentRepository, DocumentRepository>();
作業需求
如果您要根據 CRUD 的結果做出決策 (建立、讀取、更新、刪除) 作業,請使用 OperationAuthorizationRequirement 協助程式類別。 此類別可讓您撰寫單一處理程式,而不是每個作業類型的個別類別。 若要使用它,請提供一些作業名稱:
public static class Operations
{
public static OperationAuthorizationRequirement Create =
new OperationAuthorizationRequirement { Name = nameof(Create) };
public static OperationAuthorizationRequirement Read =
new OperationAuthorizationRequirement { Name = nameof(Read) };
public static OperationAuthorizationRequirement Update =
new OperationAuthorizationRequirement { Name = nameof(Update) };
public static OperationAuthorizationRequirement Delete =
new OperationAuthorizationRequirement { Name = nameof(Delete) };
}
處理常式實作方式如下,使用 OperationAuthorizationRequirement
需求和資源 Document
:
public class DocumentAuthorizationCrudHandler :
AuthorizationHandler<OperationAuthorizationRequirement, Document>
{
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context,
OperationAuthorizationRequirement requirement,
Document resource)
{
if (context.User.Identity?.Name == resource.Author &&
requirement.Name == Operations.Read.Name)
{
context.Succeed(requirement);
}
return Task.CompletedTask;
}
}
上述處理常式會使用資源、使用者的 identity 和需求的 Name
屬性來驗證作業。
操作資源處理常式的挑戰與禁止
本節說明如何處理挑戰和禁止動作結果,以及挑戰和禁止有何差異。
如要呼叫作業性資源處理常式,請在頁面處理常式或動作中叫用 AuthorizeAsync
時指定作業。 下列範例會判斷是否允許已驗證的使用者檢視所提供的文件。
注意
下列程式碼範例假設驗證已執行並設定 User
屬性。
public async Task<IActionResult> OnGetAsync(Guid documentId)
{
Document = _documentRepository.Find(documentId);
if (Document == null)
{
return new NotFoundResult();
}
var authorizationResult = await _authorizationService
.AuthorizeAsync(User, Document, Operations.Read);
if (authorizationResult.Succeeded)
{
return Page();
}
else if (User.Identity.IsAuthenticated)
{
return new ForbidResult();
}
else
{
return new ChallengeResult();
}
}
如果授權成功,則會傳回檢視文件的頁面。 如果授權失敗,但使用者有經過驗證,則傳回 ForbidResult
會通知任何驗證中介軟體授權失敗。 必須執行驗證時,會傳回 ChallengeResult
。 針對互動式瀏覽器用戶端,將使用者重新導向至登入頁面可能較適合。