承認された回答(https://stackoverflow.com/a/41348219/4974715)は、「CanReadResource」がクレームとして使用されているため、現実的に保守可能または適切ではありません(ただし、実際にはIMOのポリシーである必要があります)。回答でのアプローチは、それが使用された方法でOKではありません。アクションメソッドが多くの異なるクレームセットアップを必要とする場合、その回答では、次のようなものを繰り返し記述する必要があるためです...
[ClaimRequirement(MyClaimTypes.Permission, "CanReadResource")]
[ClaimRequirement(MyClaimTypes.AnotherPermision, "AnotherClaimVaue")]
//and etc. on a single action.
では、どれだけのコーディングが必要になるか想像してみてください。理想的には、「CanReadResource」は、ユーザーがリソースを読み取ることができるかどうかを判断するために多くのクレームを使用するポリシーであると想定されています。
私がしていることは、列挙型としてポリシーを作成し、ループしてこのように要件を設定することです...
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.
*/
}
});
DefaultAuthorizationRequirementクラスは次のようになります...
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);
}
}
}
上記のコードは、データストアのポリシーへのユーザーの事前マッピングを有効にすることもできます。したがって、ユーザーのクレームを作成するときは、基本的に、ユーザーに直接または間接的に事前にマップされたポリシーを取得します(たとえば、ユーザーに特定のクレーム値があり、そのクレーム値が特定されてポリシーにマップされているため)そのクレーム値を持つユーザーにも自動マッピングを提供し、ポリシーをクレームとして登録することで、承認ハンドラで、ユーザーのクレームに要件が含まれているかどうかを簡単に確認できます。請求。これは、ポリシー要件を満たすための静的な方法です。たとえば、「名」要件は本質的に非常に静的です。そう、
[Authorize(Policy = nameof(Enumerations.Security.Policy.ViewRecord))]
動的要件は、年齢範囲などのチェックに関するものである可能性があり、そのような要件を使用するポリシーをユーザーに事前にマッピングすることはできません。
動的ポリシーのクレームチェックの例(たとえば、ユーザーが18歳を超えているかどうかをチェックするため)は、@ blowdart(https://stackoverflow.com/a/31465227/4974715)の回答にすでに達しています。
PS:私はこれを私の電話でタイプしました。タイプミスやフォーマットの欠如はご容赦ください。