Как авторизовать пользователей более одного раза, используя настраиваемый атрибут авторизации?

У меня есть собственный класс атрибутов авторизации, чтобы дважды проверять isAuthorize.

Что я хочу:

1) Сначала он проверит, является ли пользователь super admin или нет. Если да, то ему будет authorized.

2) Если he is not , то он проверит, есть ли у него роль с именем "Deal User". Если he is not, то ему будет unauthorized.

3) Теперь, если пользователь is in играет роль "Deal User", я хочу проверить пользователя, владеет ли он сделкой или нет. Поэтому я проверяю базу данных, владеет ли пользователь этой сделкой. Если he owns , то ему будет authorized. В противном случае ему будет Unauthorized.

public class DealManageCustomAuthorizeAttribute : AuthorizeAttribute

{

    private static ApplicationDbContext Context = new ApplicationDbContext();
    private static UserStore<ApplicationUser> userStore = new UserStore<ApplicationUser>(Context);
    private UserManager<ApplicationUser> userManager = new UserManager<ApplicationUser>(userStore);

    private enum Result
    {
        Authorize,
        Unauthorize,
        InternalServerError
    }

    public override void OnAuthorization(HttpActionContext actionContext)
    {

        var result = AuthorizeRequest(actionContext);
        if (result == Result.Authorize)
        {
            return;
        }
        else
        {
            HandleUnauthorizedRequest(actionContext);
        }

    }

    protected override void HandleUnauthorizedRequest(System.Web.Http.Controllers.HttpActionContext actionContext)
    {
        //Code to handle unauthorized request
        base.HandleUnauthorizedRequest(actionContext);
    }

    private Result AuthorizeRequest(System.Web.Http.Controllers.HttpActionContext actionContext)
    {
        base.Roles = "Super Admin";
        bool authorized = base.IsAuthorized(actionContext);
        if (!authorized)
        {
            try
            {

                base.Roles = "Deal User";

                bool auth = base.IsAuthorized(actionContext);

                if (!auth)
                {
                    return Result.Unauthorize;
                }

                Uri uri = actionContext.Request.RequestUri;
                Guid dealId = new Guid(HttpUtility.ParseQueryString(uri.Query).Get("dealId"));
                string userId = HttpContext.Current.User.Identity.GetUserId();

                var retval = new Deal(Common.Common.TableSureConnectionString).CheckDealByIdAndUserId(dealId, userId);

                if (retval)
                {
                    return Result.Authorize;
                }
                return Result.Unauthorize;
            }
            catch (Exception)
            {
                return Result.InternalServerError;
            }
        }
        return Result.Authorize;
    }

}

Я написал код, и он работает. Но я хочу знать, является ли это правильным способом авторизации пользователей?


person Bimal Das    schedule 11.07.2016    source источник


Ответы (1)


Непонятно, почему именно ваш пользовательский атрибут авторизации не работает, но ясно, что его реализация слишком сложна.

AuthorizeAttribute имеет простую логическую функцию IsAuthorized, которую вы можете (и должны) переопределить, чтобы возвращать независимо от того, авторизован ли пользователь. Базовая реализация уже проверяет

  1. Авторизован ли пользователь.
  2. Находится ли пользователь в одной из предоставленных ролей.

поэтому все, что вам нужно сделать, это добавить дополнительную логику, когда пользователь находится в роли пользователя сделки.

Вам не следует никогда обращаться к статическому члену HttpContext.Current в Web API/MVC. В данном конкретном случае actionContext передается как параметр, который вы можете (и должны) использовать.

using Microsoft.AspNet.Identity;
using System;
using System.Linq;
using System.Net.Http;
using System.Security.Principal;
using System.Web.Http;
using System.Web.Http.Controllers;

[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, AllowMultiple = true)]
public class DealManageCustomAuthorizeAttribute : AuthorizeAttribute
{
    public DealManageCustomAuthorizeAttribute()
    {
        // Set the Super Admin and Deal User roles
        this.Roles = "Super Admin,Deal User";
    }

    protected override bool IsAuthorized(HttpActionContext actionContext)
    {
        // This checks whether the user is logged in, and whether
        // they are in the Super Admin or Deal User role.
        var isAuthorized = base.IsAuthorized(actionContext);

        IPrincipal user = actionContext.ControllerContext.RequestContext.Principal;

        // Special case - user is in the Deal User role
        if (isAuthorized && user.IsInRole("Deal User"))
        {

            var queryString = actionContext.Request.GetQueryNameValuePairs()
                .ToDictionary(kv => kv.Key, kv => kv.Value, StringComparer.OrdinalIgnoreCase);

            // Ensure the query string contains the key "dealId"
            if (!queryString.ContainsKey("dealId"))
            {
                return false;
            }

            Guid dealId;
            if (!Guid.TryParse(queryString["dealId"], out dealId))
            {
                // If the Guid cannot be parsed, return unauthorized
                return false;
            }

            // Now check whether the deal is authorized.
            var userId = user.Identity.GetUserId();

            return new Deal(Common.Common.TableSureConnectionString)
                .CheckDealByIdAndUserId(dealId, userId);
        }

        return isAuthorized;
    }
}
person NightOwl888    schedule 11.07.2016
comment
Ой. вы сэкономили мое время... работает нормально. Один вопрос. Я не понимаю использование использования атрибутов. - person Bimal Das; 12.07.2016
comment
См. документ MSDN. AttributeUsage просто сообщает компилятору, что атрибут действителен для метода (действия) или класса (контроллера). В последнем случае вы можете авторизовать весь контроллер с помощью одного атрибута. Например, это недопустимо, если вы попытаетесь поместить его в свойство или сборку — вы получите ошибку компилятора. Поскольку это также фильтр, он может также быть зарегистрированным для всего приложения. - person NightOwl888; 12.07.2016