J'essaie de créer un attribut d'autorisation personnalisé dans ASP.NET Core. Dans les versions précédentes, il était possible de passer outre bool AuthorizeCore(HttpContextBase httpContext)
. Mais cela n'existe plus en AuthorizeAttribute
.
Quelle est l'approche actuelle pour créer un AuthorizeAttribute personnalisé?
Ce que j'essaie d'accomplir: je reçois un ID de session dans l'autorisation d'en-tête. À partir de cet ID, je saurai si une action particulière est valide.
Réponses:
L'approche recommandée par l'équipe ASP.Net Core consiste à utiliser la nouvelle conception de stratégie qui est entièrement documentée ici . L'idée de base derrière la nouvelle approche est d'utiliser le nouvel attribut [Autoriser] pour désigner une "politique" (par exemple,
[Authorize( Policy = "YouNeedToBe18ToDoThis")]
où la politique est enregistrée dans le Startup.cs de l'application pour exécuter un bloc de code (c'est-à-dire que l'utilisateur a une revendication d'âge). lorsque l'âge est de 18 ans ou plus).La conception de la politique est un excellent ajout au cadre et l'équipe ASP.Net Security Core doit être félicitée pour son introduction. Cela dit, il n'est pas adapté à tous les cas. L'inconvénient de cette approche est qu'elle ne fournit pas de solution pratique pour le besoin le plus courant de simplement affirmer qu'un contrôleur ou une action donné nécessite un type de revendication donné. Dans le cas où une application peut avoir des centaines d'autorisations discrètes régissant les opérations CRUD sur des ressources REST individuelles ("CanCreateOrder", "CanReadOrder", "CanUpdateOrder", "CanDeleteOrder", etc.), la nouvelle approche nécessite soit une répétition de une à une. un mappage entre un nom de politique et un nom de revendication (par exemple
options.AddPolicy("CanUpdateOrder", policy => policy.RequireClaim(MyClaimTypes.Permission, "CanUpdateOrder));
), ou en écrivant du code pour effectuer ces enregistrements au moment de l'exécution (par exemple, lire tous les types de revendications dans une base de données et effectuer l'appel susmentionné en boucle). Le problème avec cette approche dans la majorité des cas, c'est qu'il s'agit de frais généraux inutiles.Bien que l'équipe ASP.Net Core Security recommande de ne jamais créer votre propre solution, dans certains cas, cela peut être l'option la plus prudente pour commencer.
Voici une implémentation qui utilise IAuthorizationFilter pour fournir un moyen simple d'exprimer une exigence de revendication pour un contrôleur ou une action donnée:
la source
new ForbidResult()
ne fonctionne donc pas (provoque l'exception / 500) car il n'a pas de schéma d'autorisation associé. Que devrais-je utiliser pour ce cas?Je suis le responsable de la sécurité d'asp.net.
Tout d'abord, permettez-moi de m'excuser qu'aucun de ces éléments n'est encore documenté en dehors de l'échantillon ou des tests unitaires du magasin de musique, et tout cela est encore en cours de perfectionnement en termes d'API exposées.La documentation détaillée est ici .Nous ne voulons pas que vous écriviez des attributs d'autorisation personnalisés. Si vous devez le faire, nous avons fait quelque chose de mal. Au lieu de cela, vous devez rédiger des exigences d' autorisation .
L'autorisation agit sur les identités. Les identités sont créées par authentification.
Vous dites dans les commentaires que vous souhaitez vérifier un ID de session dans un en-tête. Votre identifiant de session serait la base de l'identité. Si vous vouliez utiliser l'
Authorize
attribut, vous écririez un middleware d'authentification pour prendre cet en-tête et le transformer en authentifiéClaimsPrincipal
. Vous vérifieriez ensuite cela à l'intérieur d'une exigence d'autorisation. Les exigences d'autorisation peuvent être aussi compliquées que vous le souhaitez, par exemple en voici une qui prend une date de naissance sur l'identité actuelle et autorisera si l'utilisateur a plus de 18 ans;Ensuite, dans votre
ConfigureServices()
fonction, vous le câbleriezEt enfin, appliquez-le à un contrôleur ou à une méthode d'action avec
la source
ManageStore
exigence de Music Store. Comme c'est dans l'exemple, il n'y a qu'un moyen de «permettre tout ou rien» de le faire. Faut-il alors créer une nouvelle politique pour chaque permutation possible? c'est-à-dire "Utilisateurs / Lire", "Utilisateurs / Créer", "Utilisateurs / Attribuer le rôle", "Utilisateurs / Supprimer" si nous voulons des revendications précises? Sonne comme un travail de configuration pour le faire fonctionner et une abondance de politiques juste pour gérer les revendications plutôt qu'un[ClaimsAutzorization("User", "Read", "Create", "Delete", "Assign")]
attribut?[CustomAuthorize(Operator.And, Permission.GetUser, Permission.ModifyUser)]
. Je pourrais utiliser un seul attribut personnalisé dans un nombre infini de façons simplement en modifiant les paramètres du constructeur.IAuthorizeData.Policy
) et des fournisseurs de politiques personnalisés pour surmonter cette omission flagrante, plutôt que de la traiter dans le cadre. Je pensais que nous n'étions pas censés créer nos propres implémentations? Vous n'avez laissé à plusieurs d'entre nous le choix que de réimplémenter (à nouveau) l'autorisation à partir de zéro, et cette fois sans même bénéficier de l'ancienAuthorize
attribut de l' API Web . Maintenant, nous devons le faire au niveau du filtre d'action ou du middleware.Il semble qu'avec ASP.NET Core 2, vous pouvez à nouveau hériter
AuthorizeAttribute
, il vous suffit juste d'implémenterIAuthorizationFilter
(ouIAsyncAuthorizationFilter
):la source
OnAuthorization
implémentation doit attendre une méthode asynchrone, vous devez l'implémenterIAsyncAuthorizationFilter
au lieu deIAuthorizationFilter
sinon votre filtre s'exécutera de manière synchrone et votre action de contrôleur s'exécutera quel que soit le résultat du filtre.Sur la base de la bonne réponse de Derek Greer , je l'ai fait avec des énumérations.
Voici un exemple de mon code:
la source
Vous pouvez créer votre propre AuthorizationHandler qui trouvera des attributs personnalisés sur vos contrôleurs et actions et les transmettre à la méthode HandleRequirementAsync.
Ensuite, vous pouvez l'utiliser pour tous les attributs personnalisés dont vous avez besoin sur vos contrôleurs ou actions. Par exemple, pour ajouter des exigences d'autorisation. Créez simplement votre attribut personnalisé.
Créez ensuite une exigence à ajouter à votre politique
Créez ensuite le AuthorizationHandler pour votre attribut personnalisé, en héritant du AttributeAuthorizationHandler que nous avons créé précédemment. Il sera transmis un IEnumerable pour tous vos attributs personnalisés dans la méthode HandleRequirementsAsync, accumulés à partir de votre contrôleur et de votre action.
Enfin, dans votre méthode ConfigureServices Startup.cs, ajoutez votre AuthorizationHandler personnalisé aux services et ajoutez votre stratégie.
Maintenant, vous pouvez simplement décorer vos contrôleurs et actions avec votre attribut personnalisé.
la source
Facile: ne créez pas le vôtre
AuthorizeAttribute
.Pour les scénarios d'autorisation purs (comme restreindre l'accès à des utilisateurs spécifiques uniquement), l'approche recommandée consiste à utiliser le nouveau bloc d'autorisation: https://github.com/aspnet/MusicStore/blob/1c0aeb08bb1ebd846726232226279bbe001782e1/samples/MusicStore/Startup.cs#L84 -L92
Pour l'authentification, il est préférable de le gérer au niveau du middleware.
Qu'essayez-vous de réaliser exactement?
la source
Si quelqu'un veut simplement valider un jeton au porteur dans la phase d'autorisation en utilisant les pratiques de sécurité actuelles, vous pouvez,
ajoutez ceci à votre Startup / ConfigureServices
et cela dans votre base de code,
Si le code n'atteint pas,
context.Succeed(...)
il échouera quand même (401).Et puis dans vos contrôleurs, vous pouvez utiliser
la source
La méthode moderne est AuthenticationHandlers
dans startup.cs add
IUserService est un service que vous créez lorsque vous avez un nom d'utilisateur et un mot de passe. Fondamentalement, il renvoie une classe d'utilisateurs que vous utilisez pour mapper vos revendications.
Ensuite, vous pouvez interroger ces revendications et toutes les données que vous avez mappées, il y en a plusieurs, jetez un œil à la classe ClaimTypes
vous pouvez l'utiliser dans une méthode d'extension et obtenir l'un des mappages
Cette nouvelle façon, je pense que c'est mieux que
la source
Au moment d'écrire ces lignes, je pense que cela peut être accompli avec l'interface IClaimsTransformation dans asp.net core 2 et au-dessus. Je viens de mettre en œuvre une preuve de concept qui est suffisamment partageable pour être publiée ici.
Pour l'utiliser dans votre contrôleur, ajoutez simplement une
[Authorize(Roles="whatever")]
méthode appropriée à vos méthodes.Dans notre cas, chaque demande comprend un en-tête d'autorisation qui est un JWT. Ceci est le prototype et je crois que nous ferons quelque chose de très proche de cela dans notre système de production la semaine prochaine.
Futurs électeurs, pensez à la date de rédaction lorsque vous votez. À ce jour, this
works on my machine.
™ Vous voudrez probablement plus de gestion des erreurs et de journalisation de votre implémentation.la source
Pour autorisation dans notre application. Nous avons dû appeler un service basé sur les paramètres passés dans l'attribut d'autorisation.
Par exemple, si nous voulons vérifier si un médecin connecté peut voir les rendez-vous des patients, nous passerons "View_Appointment" à l'attribut d'autorisation personnalisé et vérifierons ce droit dans le service DB et en fonction des résultats, nous autoriserons. Voici le code de ce scénario:
Et sur l'action de l'API, nous l'utilisons comme ceci:
la source
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 ...
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 ...
La classe DefaultAuthorizationRequirement ressemble à ...
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,
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.
la source