web-dev-qa-db-fra.com

Création d'un AuthorizeAttribute personnalisé dans une API Web (.Net Framework)

J'utilise OAuth2.0 Owin (accord de mot de passe) dans mon WebAPI. Mon jeton initial est comme ci-dessous.

{
    "access_token": "_ramSlQYasdsRTWEWew.....................",
    "token_type": "bearer",
    "expires_in": 17999,
    "permissions": {
        "user": [
            "Add",
            "Update",
            "Delete"
        ],
        "Product": [
            "Read",
            "Create"
        ]
    }
}

J'ai personnalisé la réponse en créant une nouvelle clé appelée permissions qui contient les privilèges de l'utilisateur correspondant.

À partir de là, je dois valider chaque demande de mon Resource server en vérifiant si l'utilisateur dispose des autorisations suffisantes pour appeler l'API à l'aide de l'attribut Autoriser.

J'ai trouvé un exemple similaire dans ici où il est question de Dot Net Core, qui ne convient pas à mon cas.

La partie difficile est que la permission JSON Key est elle-même un complexe avec ArrayList

[CustomAuthorize(PermissionItem.Product, PermissionAction.Read)]
    public async Task<IActionResult> Index()
    {
        return View(Index);
    }

public class CustomAuthorize : AuthorizeAttribute {
    public AuthorizeAttribute (PermissionItem item, PermissionAction action) {
        //Need to initalize the Permission Enums
    }
    public override void OnAuthorization (HttpActionContext actionContext) {
        //Code to get the value from Permissions ArrayList and compare it with the Enum values
    }
}

Ce qui précède est l'idée que j'ai. Mais en raison de la complexité de la comparaison Permissions Key et Enum, je ne pouvais pas avancer.

De plus, il y a une question du type Si l'autorisation pour l'utilisateur est Ajouter, ainsi que la mise à jour signifie que je dois créer deux conditions d'attribut avant mon contrôleur.

Comme

[CustomAuthorize(PermissionItem.User, PermissionAction.Add)]
[CustomAuthorize(PermissionItem.User, PermissionAction.Update)]

Ce qui conduit à ajouter plus de lignes d'attributs. Donc, y a-t-il un moyen de le faire comme dans une seule condition avec | séparés?

[CustomAuthorize(PermissionItem.User, PermissionAction.Update|PermissionAction.Add)]
9
Jayendran

Nous avons créé ci-dessous un filtre API pour l'authentification.

Ici, "SecretToken", "MerchantKey", ces deux clés transmettent une demande d'API. nous validons ces deux à partir de la base de données en utilisant la fonction "IsValidMerchant".

IsValidMerchant cette fonction connecte directement à la table de base de données où les valeurs respectives sont stockées

public void OnAuthorization(AuthorizationFilterContext actionContext)
{
  const string secretTokenName = "SecretToken";
  const string merchentKeyName = "MerchantKey";
  bool isValid = false;

  if (!actionContext.Filters.Any(item => item is IAllowAnonymousFilter))
    {
     CPServiceResponse response = new CPServiceResponse();
     var secretToken = actionContext.HttpContext.Request.Headers[secretTokenName].FirstOrDefault();
     var merchentKey = actionContext.HttpContext.Request.Headers[merchentKeyName].FirstOrDefault();

      isValid = this.IsValidMerchant(merchentKey, secretToken,_productCode);

       if (isValid == false)
        {
          response.Status = (int)HttpStatusCode.Unauthorized;
          response.Message = Hegic.Shared.Resource.Common.UnauthorizedRequestError;
          actionContext.Result = new JsonResult("")
                {
                    Value = new { Status = response }
                };
         }
      }
  }
1
Parth Akbari

Vous pourriez nous faire des drapeaux et des opérations binaires pour vous permettre de | les différentes opérations ensemble.

Le code suivant montre un petit exemple de la façon dont cela pourrait être fait

class Program {
    static void Main(string[] args) {
        Test test = new Test();
        CustomAuthorizeAttribute customAuthorizeAttribute = (CustomAuthorizeAttribute)Attribute.GetCustomAttribute(typeof(Test), typeof(CustomAuthorizeAttribute));

        customAuthorizeAttribute.Test();

        Console.ReadKey();
    }
}

[CustomAuthorize(PermissionActions = PermissionAction.Add | PermissionAction.Delete)]
public class Test {

}

public class CustomAuthorizeAttribute : Attribute {
    public PermissionAction PermissionActions { get; set; }

    public void Test() {
        if ((PermissionActions & PermissionAction.Add) == PermissionAction.Add) Console.WriteLine("Add");
        if ((PermissionActions & PermissionAction.Delete) == PermissionAction.Delete) Console.WriteLine("Delete");
        if ((PermissionActions & PermissionAction.Update) == PermissionAction.Update) Console.WriteLine("Update");
    }
}

public enum PermissionAction {
    Add = 1,
    Update = 2,
    Delete = 4
}

Ce qui donne la sortie suivante

 enter image description here

0
3dd

Pourquoi n'autorisez-vous pas votre constructeur CustomAuthorize à avoir plusieurs actions d'autorisation?.

public class CustomAuthorize : AuthorizeAttribute
{
    private readonly PermissionAction[] permissionActions;

    public CustomAuthorize(PermissionItem item, params PermissionAction[] permissionActions)
    {
        this.permissionActions = permissionActions;
    }

    public override void OnAuthorization(HttpActionContext actionContext)
    {
        var currentIdentity = System.Threading.Thread.CurrentPrincipal.Identity;
        if (!currentIdentity.IsAuthenticated) {
            // redirect to access denied page
        }

        var userName = currentIdentity.Name;
        // step 1 : retrieve user object

        // step 2 : retrieve user permissions

        // step 3 : match user permission(s) agains class/method's required premissions

        // step 4 : continue/redirect to access denied page
    }
}

Et vous annoterez votre classe avec: [CustomAuthorize(PermissionItem.User, PermissionAction.Update, PermissionAction.Add)]

Je ne suis pas sûr de ce que OP veut réaliser ici. Si vous comptez sur une requête HTTP pour fournir des droits d'accès, il s'agit d'un BIG SECURITY HOLE. Lors de chaque demande, vous devez récupérer les informations sur les droits d'accès de l'utilisateur dans la base de données, puis les faire correspondre à l'autorisation requise par la classe/méthode. 

En règle générale, vous ne devez pas vous fier à l'objet de la requête pour vous indiquer les autorisations dont dispose l'utilisateur actuel. Vous devriez les récupérer à partir du magasin de données.

Ma mise en œuvre de CustomAttribute

public class CustomAuthorize : System.Web.Http.AuthorizeAttribute
{
    private readonly PermissionAction[] permissionActions;

    public CustomAuthorize(PermissionItem item, params PermissionAction[] permissionActions)
    {
        this.permissionActions = permissionActions;
    }

    protected override Boolean IsAuthorized(HttpActionContext actionContext)
    {
        var currentIdentity = actionContext.RequestContext.Principal.Identity;
        if (!currentIdentity.IsAuthenticated)
            return false;

        var userName = currentIdentity.Name;
        using (var context = new DataContext())
        {
            var userStore = new UserStore<AppUser>(context);
            var userManager = new UserManager<AppUser>(userStore);
            var user = userManager.FindByName(userName);

            if (user == null)
                return false;

            foreach (var role in permissionActions)
                if (!userManager.IsInRole(user.Id, Convert.ToString(role)))
                    return false;

            return true;
        }
    }
}
0
Dipen Shah