Jawaban yang diterima ( https://stackoverflow.com/a/41348219/4974715 ) tidak dapat dipertahankan atau cocok secara realistis karena "CanReadResource" digunakan sebagai klaim (tetapi pada dasarnya harus merupakan kebijakan dalam kenyataannya, IMO). Pendekatan pada jawaban tidak OK dalam cara itu digunakan, karena jika metode tindakan memerlukan banyak pengaturan klaim yang berbeda, maka dengan jawaban itu Anda harus berulang kali menulis sesuatu seperti ...
[ClaimRequirement(MyClaimTypes.Permission, "CanReadResource")]
[ClaimRequirement(MyClaimTypes.AnotherPermision, "AnotherClaimVaue")]
//and etc. on a single action.
Jadi, bayangkan berapa banyak pengkodean yang akan diambil. Idealnya, "CanReadResource" seharusnya merupakan kebijakan yang menggunakan banyak klaim untuk menentukan apakah pengguna dapat membaca sumber daya.
Apa yang saya lakukan adalah saya membuat kebijakan saya sebagai enumerasi dan kemudian loop melalui dan mengatur persyaratan seperti ...
services.AddAuthorization(authorizationOptions =>
{
foreach (var policyString in Enum.GetNames(typeof(Enumerations.Security.Policy)))
{
authorizationOptions.AddPolicy(
policyString,
authorizationPolicyBuilder => authorizationPolicyBuilder.Requirements.Add(new DefaultAuthorizationRequirement((Enumerations.Security.Policy)Enum.Parse(typeof(Enumerations.Security.Policy), policyWrtString), DateTime.UtcNow)));
/* Note that thisn does not stop you from
configuring policies directly against a username, claims, roles, etc. You can do the usual.
*/
}
});
Kelas DefaultAuthorizationRequirement terlihat seperti ...
public class DefaultAuthorizationRequirement : IAuthorizationRequirement
{
public Enumerations.Security.Policy Policy {get; set;} //This is a mere enumeration whose code is not shown.
public DateTime DateTimeOfSetup {get; set;} //Just in case you have to know when the app started up. And you may want to log out a user if their profile was modified after this date-time, etc.
}
public class DefaultAuthorizationHandler : AuthorizationHandler<DefaultAuthorizationRequirement>
{
private IAServiceToUse _aServiceToUse;
public DefaultAuthorizationHandler(
IAServiceToUse aServiceToUse
)
{
_aServiceToUse = aServiceToUse;
}
protected async override Task HandleRequirementAsync(AuthorizationHandlerContext context, DefaultAuthorizationRequirement requirement)
{
/*Here, you can quickly check a data source or Web API or etc.
to know the latest date-time of the user's profile modification...
*/
if (_aServiceToUse.GetDateTimeOfLatestUserProfileModication > requirement.DateTimeOfSetup)
{
context.Fail(); /*Because any modifications to user information,
e.g. if the user used another browser or if by Admin modification,
the claims of the user in this session cannot be guaranteed to be reliable.
*/
return;
}
bool shouldSucceed = false; //This should first be false, because context.Succeed(...) has to only be called if the requirement specifically succeeds.
bool shouldFail = false; /*This should first be false, because context.Fail()
doesn't have to be called if there's no security breach.
*/
// You can do anything.
await doAnythingAsync();
/*You can get the user's claims...
ALSO, note that if you have a way to priorly map users or users with certain claims
to particular policies, add those policies as claims of the user for the sake of ease.
BUT policies that require dynamic code (e.g. checking for age range) would have to be
coded in the switch-case below to determine stuff.
*/
var claims = context.User.Claims;
// You can, of course, get the policy that was hit...
var policy = requirement.Policy
//You can use a switch case to determine what policy to deal with here...
switch (policy)
{
case Enumerations.Security.Policy.CanReadResource:
/*Do stuff with the claims and change the
value of shouldSucceed and/or shouldFail.
*/
break;
case Enumerations.Security.Policy.AnotherPolicy:
/*Do stuff with the claims and change the
value of shouldSucceed and/or shouldFail.
*/
break;
// Other policies too.
default:
throw new NotImplementedException();
}
/* Note that the following conditions are
so because failure and success in a requirement handler
are not mutually exclusive. They demand certainty.
*/
if (shouldFail)
{
context.Fail(); /*Check the docs on this method to
see its implications.
*/
}
if (shouldSucceed)
{
context.Succeed(requirement);
}
}
}
Perhatikan bahwa kode di atas juga dapat memungkinkan pra-pemetaan pengguna ke kebijakan di penyimpanan data Anda. Jadi, ketika membuat klaim untuk pengguna, Anda pada dasarnya mengambil kebijakan yang telah dipetakan sebelumnya ke pengguna secara langsung atau tidak langsung (misalnya karena pengguna memiliki nilai klaim tertentu dan bahwa nilai klaim telah diidentifikasi dan dipetakan ke suatu kebijakan, seperti bahwa ia menyediakan pemetaan otomatis untuk pengguna yang memiliki nilai klaim juga), dan mendaftar kebijakan sebagai klaim, sehingga dalam penangan otorisasi, Anda dapat dengan mudah memeriksa apakah klaim pengguna mengandung persyaratan. Kebijakan sebagai Nilai dari item Klaim dalam klaim. Itu untuk cara statis untuk memenuhi persyaratan kebijakan, misalnya persyaratan "Nama depan" cukup statis. Begitu,
[Authorize(Policy = nameof(Enumerations.Security.Policy.ViewRecord))]
Persyaratan dinamis dapat tentang memeriksa rentang usia, dll. Dan kebijakan yang menggunakan persyaratan tersebut tidak dapat dipetakan sebelumnya kepada pengguna.
Contoh pemeriksaan klaim kebijakan dinamis (mis. Untuk memeriksa apakah pengguna berusia di atas 18 tahun) sudah ada di jawaban yang diberikan oleh @blowdart ( https://stackoverflow.com/a/31465227/4974715 ).
PS: Saya mengetik ini di ponsel saya. Maafkan kesalahan ketik dan kurangnya format.