Получите Owin IIdentity от IHttpHandler

Принятое ответное примечание:

Хотя я по достоинству оценил помощь в создании собственного OwinMiddleware для отправки изображений после выполнения некоторых проверок вместо IHttpModule, что не решает проблему полностью.

Дело в том, что я добавил заголовок авторизации в запросы ajax, и внутри этого заголовка я отправляю свой токен-носитель, чтобы я мог получать информацию о пользователях из Owin. Поэтому я должен добавить этот заголовок в запросы изображения, чтобы иметь возможность получать информацию о пользователях из промежуточного программного обеспечения обработчика изображений.


Оригинальный вопрос:

Я следую за этим сообщением в блоге, чтобы создать аутентификацию на основе токенов для моего веб-проекта. Потому что некоторые ресурсы моего веб-API будут использоваться родными мобильными клиентами. И я слышал, что аутентификация на основе токенов - это способ пойти на это. И в моем собственном проекте у меня есть обработчик запроса пользовательского изображения. И нужна зарегистрированная информация пользователя внутри этого обработчика. Но когда я пытаюсь извлечь информацию из билета, я получаю null. И я не уверен в этом, но, я думаю, у меня есть 2 разных объекта IIdentity, и мне нужен тот, который хранится внутри Owin Context.

Здесь позвольте мне показать вам некоторые коды;

Мой GrantResourceOwnerCredentials, который хранит претензии в ClaimsIdentity,

    public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
        {
....
// checking user credentials and get user information into 'usr' variable
....

            var identity = new ClaimsIdentity(context.Options.AuthenticationType);
            identity.AddClaim(new Claim(ClaimTypes.Name, context.UserName));
            identity.AddClaim(new Claim(ClaimTypes.Role, "user"));
            identity.AddClaim(new Claim("sub", context.UserName));
            identity.AddClaim(new Claim(ClaimTypes.Sid, usr.UserId.ToString()));

            var props = new AuthenticationProperties(new Dictionary<string, string>
                {
                    {
                        "as:client_id", (context.ClientId == null) ? string.Empty : context.ClientId
                    },
                    {
                        "userId", usr.UserId.ToString()
                    }
                });

            var ticket = new AuthenticationTicket(identity, props);
            context.Validated(ticket);
}

Вспомогательная функция для извлечения идентификатора пользователя из данного объекта IIdentity

public class utils {
    public Guid? GetUserIdFromTicket(IIdentity identity)
    {
        var cId = (ClaimsIdentity)identity;
        var uid = cId.FindFirst(ClaimTypes.Sid);

        if (uid != null && Comb.IsComb(uid.Value))
            return new Guid(uid.Value);
        else
            return null;
    }
....
}

Теперь я могу получить loggedUserId с моего контроллера,

    var loggedUserId = utils.GetUserIdFromTicket(User.Identity);

но если я позвоню ему из моего IHttpHandler, я получу нуль,

    public class ImageHandler : IHttpHandler
    {
        public ImageHandler()
        {
        }

        public ImageHandler(RequestContext requestContext)
        {
            RequestContext = requestContext;
        }

        protected RequestContext RequestContext { get; set; }

        public utils utils = new utils(); // changed name for simplicity.

        public void ProcessRequest(HttpContext context)
        {
            var strUserId = RequestContext.RouteData.Values["userid"].ToString();
            var strContentId = RequestContext.RouteData.Values["contentid"].ToString();
            var fileName = RequestContext.RouteData.Values["filename"].ToString();
            var size = RequestContext.RouteData.Values["size"].ToString();

            var loggedUserId = utils.GetUserIdFromTicket(context.User.Identity);

....
image processing
....
            context.Response.End();
        }

}

Надеюсь, я не испортил это навсегда...

Решение:

Я выполнил свое собственное промежуточное программное обеспечение для обслуживания изображений для моих пользователей после выполнения некоторых проверок. Вот моя задача выполнения Invoke. Все остальное так же, как рекомендовано в принятом ответе. Но, как указано выше, для этого я должен отправить изображения с заголовком Authorization, или loggedUserId снова будет null.

public async override Task Invoke(IOwinContext context)
{
    // need to interrupt image requests having src format : http://www.mywebsite.com/myapp-img/{userid}/{contentId}/{fileName}/{size}/
    if (context.Request.Path.HasValue && context.Request.Path.Value.IndexOf("myapp-img") > -1)
    {
        // get values from url.
        var pathValues = context.Request.Path.Value.Split('/');
        var strUserId = pathValues[2].ToString();
        var strContentId = pathValues[3].ToString();
        var fileName = pathValues[4].ToString();
        var size = pathValues[5].ToString();

        // check if code returned a notfound or unauthorized image as response.
        var hasError = false;

        // get userId from static utils class providing current owin identity object
        var loggedUserId = ChildOnBlogUtils.GetUserIdFromTicket(context.Request.User.Identity);

        // save root path of application to provide error images.
        var rootPath = AppDomain.CurrentDomain.SetupInformation.ApplicationBase;

        // assign content type of response to requested file type
        context.Response.ContentType = ChildOnBlogUtils.GetContentType(context.Request.Path.Value.ToString());

        // if user requested thumbnail send it without doing checks
        if (size == "thumb")
        {
            imgPath = "images/" + strUserId.ToLower() + "/thumbnail/" + fileName;
        }
        else
        {
            var canSee = false;

            // check if user can see the content and put the result into canSee variable
            // I am using loggedUserId inside these checks
            ...
            ...
            // end checks

            if (canSee)
            {
                // removed some more checks here for simplicity
                imgPath = "images/" + strUserId.ToLower() + "/" + fileName;
            }
            else
            {
                context.Response.ContentType = "Image/png";
                var imgData = File.ReadAllBytes(rootPath + "/images/unauthorized.png");
                await context.Response.Body.WriteAsync(imgData, 0, imgData.Length);
                hasError = true;
            }
        }

        if (!hasError) // if no errors have been risen until this point. try to provide the requested image to user.
        {
            try
            {
                var imgData = UserMediaContainer.GetFileContent(imgPath); // get file from storage account (azure)

                if (imgData.Length == 0)
                {
                    context.Response.ContentType = "Image/png";
                    imgData = File.ReadAllBytes(rootPath + "/images/notfound.png");
                    await context.Response.Body.WriteAsync(imgData, 0, imgData.Length);
                }
                else
                {
                    await context.Response.Body.WriteAsync(imgData, 0, imgData.Length);
                }
            }
            catch (Exception ex)
            {
                context.Response.ContentType = "Image/png";
                var imgData = File.ReadAllBytes(rootPath + "/images/notfound.png");
                await context.Response.Body.WriteAsync(imgData, 0, imgData.Length);
            }
        }
    }
    else if (context.Request.Path.HasValue && context.Request.Path.Value.IndexOf("profile-img") > -1)
    {
        // profile image provider. Same code as providing thumbnails.
    }
    else
    {
        // if it is not an image request to be handled. move to the next middleware.
        await Next.Invoke(context);
    }
}
+1
01 сент. '15 в 15:30
источник поделиться
1 ответ

Я предполагаю, что ваш ImageHandler обрабатывается до всего остального в конвейере owin, что означает, что он обрабатывается до того, как авторизация встанет на свои места.

Поскольку вы используете owin, я бы посоветовал вам отказаться от IHttpHandler и использовать некоторое обычное промежуточное программное обеспечение owin. Следуя этому пути, вы сможете ввести свой модуль в нужное место в конвейере.

Создание промежуточного программного обеспечения довольно просто:

public class ImageProcessingMiddleware : OwinMiddleware
{
    public ImageProcessingMiddleware(OwinMiddleware next): base(next)
    {
    }

    public async override Task Invoke(IOwinContext context)
    {
        string username = context.Request.User.Identity.Name;

        Console.WriteLine("Begin Request");
        await Next.Invoke(context);
        Console.WriteLine("End Request");
    }
}

После того, как вы определили свое промежуточное ПО, вы можете создать метод расширения для создания экземпляра:

public static class ImageProcessingExtensions
{
    public static IAppBuilder UseImageProcessing(this IAppBuilder app)
    {
        return app.Use<ImageProcessingMiddleware>();
    }
}

Теперь вы можете подключить свое промежуточное ПО в конвейере:

app.UseImageProcessing();

Если вы воспользовались примером Taiseer, вы сделали бы это после того, как вы настроили модуль авторизации:

// Token Generation
app.UseOAuthAuthorizationServer(OAuthServerOptions);
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());

Возвращаясь к промежуточному программному обеспечению, вы, возможно, заметили там метод Invoke:

public async override Task Invoke(IOwinContext context)
{
    string username = context.Request.User.Identity.Name;

    Console.WriteLine("Begin Request");
    await Next.Invoke(context);
    Console.WriteLine("End Request");
}

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

Там интересная статья о промежуточном программном обеспечении owin, которое стоит прочитать.

+1
01 сент. '15 в 20:02
источник

Посмотрите другие вопросы по меткам или Задайте вопрос