La réponse acceptée ( https://stackoverflow.com/a/41348219/4974715 ) n'est pas réaliste ni appropriée car "CanReadResource" est utilisé comme une réclamation (mais devrait essentiellement être une politique en réalité, OMI). L'approche de la réponse n'est pas correcte dans la façon dont elle a été utilisée, car si une méthode d'action nécessite de nombreuses configurations de revendications différentes, alors avec cette réponse, vous devrez écrire à plusieurs reprises quelque chose comme ...
[ClaimRequirement(MyClaimTypes.Permission, "CanReadResource")]
[ClaimRequirement(MyClaimTypes.AnotherPermision, "AnotherClaimVaue")]
//and etc. on a single action.
Alors, imaginez combien de codage cela prendrait. Idéalement, «CanReadResource» est censé être une stratégie qui utilise de nombreuses revendications pour déterminer si un utilisateur peut lire une ressource.
Ce que je fais, c'est que je crée mes politiques en tant qu'énumération, puis que je boucle et configure les exigences comme ceci ...
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.
*/
}
});
La classe DefaultAuthorizationRequirement ressemble à ...
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);
}
}
}
Notez que le code ci-dessus peut également activer le pré-mappage d'un utilisateur à une stratégie dans votre magasin de données. Ainsi, lorsque vous composez des revendications pour l'utilisateur, vous récupérez essentiellement les politiques qui ont été pré-mappées à l'utilisateur directement ou indirectement (par exemple, parce que l'utilisateur a une certaine valeur de revendication et que cette valeur de revendication a été identifiée et mappée à une politique, telle que qu'il fournit un mappage automatique pour les utilisateurs qui ont également cette valeur de revendication), et inscrivez les stratégies en tant que revendications, de telle sorte que dans le gestionnaire d'autorisations, vous pouvez simplement vérifier si les revendications de l'utilisateur contiennent des exigences.Politique comme valeur d'un élément de revendication dans leur réclamations. C'est pour une manière statique de satisfaire une exigence de politique, par exemple l'exigence de "prénom" est de nature assez statique. Donc,
[Authorize(Policy = nameof(Enumerations.Security.Policy.ViewRecord))]
Une exigence dynamique peut consister à vérifier la tranche d'âge, etc. et les politiques qui utilisent de telles exigences ne peuvent pas être pré-mappées aux utilisateurs.
Un exemple de vérification dynamique des revendications de politique (par exemple pour vérifier si un utilisateur a plus de 18 ans) se trouve déjà dans la réponse donnée par @blowdart ( https://stackoverflow.com/a/31465227/4974715 ).
PS: j'ai tapé ceci sur mon téléphone. Pardonnez les fautes de frappe et le manque de formatage.