Israel Aece

Software Developer

Cancelando Requisições do HttpClient

Como sabemos, a classe HttpClient é uma espécie de proxy para o consumo de serviços REST a partir de aplicações .NET. Durante a sua criação é possível realizar diversas configurações, e as requisições que saem e chegam, compartilham estas configurações, evitando que se faça isso a cada nova requisição/resposta que é enviada/processada.

Entre os diversos métodos que esta classe fornece, o mais completo, ou melhor, "de mais baixo nível", é o SendAsync, que onde podemos (e devemos) configurar completamente a mensagem, especificando desde a URL até o método HTTP que será utilizado. Como facilitador, existem alguns métodos que foram criados sobre o método SendAsync, e foram nomeados utilizandos os verbos do HTTP (GET (GetAsync), POST (PostAsync), etc.).

A classe HttpClient fornece um método chamado CancelPendingRequests, que como o próprio nome sugere, solicitará o cancelamento de todas as requisições que estão sendo realizadas pela respectiva instância do HttpClient. Mas é provável que queremos ter um controle individual das requisições e conseguirmos cancelar especificamente uma delas.

Felizmente todos os métodos que iniciam uma nova requisição possuem um parâmetro onde é permitido controlar e, principalmente, cancelar a execução da mesma. Eles fazem uso de uma classe chamada CancellationTokenSource, que faz parte do .NET Framework, e possibilita ao chamador informar ao runtime que deseja cancelar a requisição que está em andamento.

Para exemplificar o seu uso, vamos utilizar uma aplicação WPF para iniciará a requisição, e enquanto ela estiver sendo executada, vamos dar a possibilidade ao usuário dele conseguir cancelar a mesma. Note no código abaixo que criamos em nível da classe um membro chamado status, qual será o responsável por gerenciar um eventual cancelamento. No clique do botão Requisitar, estamos recorrendo ao método GetAsync (chamando-o de forma assíncrona) e passamos o CancellationTokenSource. É importante notar que temos que envolver este código em um bloco try/catch para interceptar a exceção do tipo TaskCanceledException, que será disparada quando o cancelamento for efetivamente realizado.

public partial class MainWindow : Window
{
    private CancellationTokenSource status;
    private HttpClient proxy = new HttpClient();

    private async void Requisitar_Click(object sender, RoutedEventArgs e)
    {
        Reinicializar();

        try
        {
            var resposta = await proxy.GetAsync(Url.Text, status.Token);

            if (resposta.IsSuccessStatusCode)
                Conteudo.Text = await resposta.Content.ReadAsStringAsync();
        }
        catch (TaskCanceledException)
        {
            Conteudo.Foreground = Brushes.Red;
            Conteudo.Text = "*** A REQUISIÇÃO FOI CANCELADA ***";
        }
    }

    private void Reinicializar()
    {
        Conteudo.Text = null;
        Conteudo.Foreground = Brushes.Black;

        status = new CancellationTokenSource();
    }

    private void Cancelar_Click(object sender, RoutedEventArgs e)
    {
        status.Cancel();
    }
}

Agora o cancelamento pode ser solicitado ao clicar no botão Cancelar, e através do método Cancel da classe CancellationTokenSource, o código para o qual passamos este token (que foi o GetAsync) identifica a solicitação e cancela a execução, disparando a exceção que falamos acima. As imagens abaixo ilustram tanto a requisição sendo executada com sucesso quanto um cancelamento sendo solicitado e acatado, abortando o processamento.



Análise de Headers antes da carga do Conteúdo

Quando fazemos a requisição através da classe HttpClient, informamos o endereço do recurso que queremos acessar, e através de algum método, como por exemplo, o GetAsync, é possível receber o resultado esperado. Apesar de na maioria das vezes já sabermos o que o teremos como resultado, em alguns momentos podemos querer fazer alguma verificação antes de materializar o conteúdo que foi retornado.

A questão é que para materializar o tal conteúdo, precisamos alocar memória e realizar algum processamento, e que pode ser desnecessário dependendo da uma eventual condição que temos que avaliar antes de efetivamente carregar o conteúdo. Para os métodos expostos pela classe HttpClient, há uma versão que nos permite passar uma das opções do enumerador HttpCompletionOption, a saber.

  • ResponseHeadersRead: indica que a operação deve ser considerada como completa depois que os headers forem lidos. A conteúdo ainda não.
  • ResponseContentRead: indica que a operação somente será considerada como completa depois que todo o corpo da mesma já tenha sido lido e materializado.

Como vamos buscar o conteúdo através do método GetAsync, iremos definir a opção ResponseHeadersRead para analisarmos os headers antes de carregar o conteúdo. Quando a requisição voltar, faremos a verificação para analisar se o conteúdo (através do header Content-Type) é ou não do tipo HTML, e se for, o acessamos da forma que desejarmos. Essa técnica evitará o carregamento desnecessário do corpo da mensagem, ou seja, postergaremos a carga até que se realmente precise dela, poupando recursos da máquina de onde o consuma está sendo realizado.

using (var client = new HttpClient())
{
    var resposta =
        await client.GetAsync("http://www.microsoft.com", HttpCompletionOption.ResponseHeadersRead);

    if (resposta.Content.Headers.ContentType.MediaType != "text/html")
    {
        var conteudo = await resposta.Content.ReadAsStringAsync();

        //utilizar o conteúdo
    }
}

Recebendo Notificações com SSE

É muito comum aplicações Web precisarem receber informações do servidor para que seja possível atualizar a página em que o usuário se encontra, ou até mesmo para receber notificações de que algo ocorreu e que isso possa interessar ao mesmo. Existem diversas técnicas que possibilitam esse objetivo, e uma das mais conhecidas é o polling, que consiste em criar um timer no cliente (HTML/JavaScript) que periodicamente verifica no servidor se há alguma atualização.

O problema desta técnica é ter que ficar gastando tempo e recurso, e dependendo da forma como as informações são disponibilizadas, podemos demandar todo este recurso para que não se receber nada. Um novo recurso, disponível a partir do HTML 5, é o Web Sockets, possui uma vasta gama de recursos, incluindo a comunicação bidirectional entre o cliente e o servidor, e pode atender completamente esta demanda. Só que em algumas vezes precisamos apenas do recebimento de informações do servidor, e o Web Sockets para soar como um excesso para essa atividade.

O HTML 5 ainda fornece um recurso chamado de Server Sent Events (SSE), e com uma API de fácil utilização, é possível estabelecer a comunicação e receber as notificações do servidor. O ASP.NET Web API também fornece uma forma de estabelecer, via stream, uma ligação com o cliente, e qualquer coisa que se escreva neste stream, o mesmo receberá e irá tratar a mesma como quiser. A finalidade deste artigo é explorar a utilização do SSE para notificar os usuários sobre novas notícias que acontecerão.



Vamos iniciar pelo lado do servidor. Iremos criar um controller no ASP.NET Web API para gerenciar os assinantes, receber as notícias e publicá-las. Podemos reparar na classe abaixo que há uma coleção chamada assinantes que armazenará os streams dos clientes conectados. O método Assinar é responsável por receber a requisição dos clientes interessados, e no construtor da classe PushStreamContent definimos um delegate que irá instanciar o StreamWriter e armazenará na coleção.

public class NoticiasController : ApiController
{
    private static ConcurrentBag<StreamWriter> assinantes = new ConcurrentBag<StreamWriter>();

    [HttpGet]
    public HttpResponseMessage Assinar(HttpRequestMessage requisicao)
    {
        return new HttpResponseMessage()
        {
            Content =
                new PushStreamContent(
                    (stream, content, context) =>
                        assinantes.Add(new StreamWriter(stream) { AutoFlush = true }),
                    "text/event-stream")
        };
    }
}

Nós já utilizamos a classe PushStreamContent no artigo que vimos como exibir vídeos pelo ASP.NET Web API, e da mesma forma aqui, o StreamWriter que ela armazenará servirá para que as strings sendo escritas nele viajem até os respectivos clientes. Por fim, o media-type text/event-stream que quando informado no Content-Type da resposta, permite aos clientes entender que esta resposta seja entendida como um canal que receberá constantes informações.

Uma vez que temos os assinantes, chega o momento da geração do conteúdo e, principalmente, a entrega das informações para os clientes. O primeiro método que vemos abaixo, AdicionarNoticia, recebe uma nova notícia, armazena em algum repositório e notificamos os clientes que estão adicionados na coleção.

[HttpPost]
public async Task AdicionarNoticia(Noticia noticia)
{
    //Armazenar em algum repositório

    await Notificar(noticia);
}

private async static Task Notificar(Noticia noticia)
{
    foreach (var assinante in assinantes.ToList())
    {
        try
        {
            await assinante.WriteAsync(
                string.Format("data: {0}\n\n", JsonConvert.SerializeObject(noticia)));
        }
        catch
        {
            StreamWriter sw = null;
            assinantes.TryTake(out sw);
        }
    }
}

O método Notificar percorre a coleção e via o método WriteAsync do Stream publicamos a nova notícia aos clientes. Como sabemos, o StreamWriter nos permite mandar strings, e através de um serializador (neste caso em formato JSON) temos a oportunidade de mandarmos objetos complexos, e como o JavaScript lida de forma fácil com este formato, não teremos muitos problemas em exibir essa informação. A única preocupação que temos que ter é com relação a como mandamos a string para o cliente, ou seja, prefixando com o "data: MensagemAqui\n\n".

Agora que já temos tudo o que é necessário do lado do servidor, chega o momento em que temos que codificar o cliente, e assim utilizando efetivamente o SSE. Infelizmente o Internet Explorer não dá suporte à este recurso, e para o exemplo, vamos utilizar o Chrome. A primeira condicional é para avaliar se o navegador dá suporte para o SSE. Caso seja suportado, então instanciamos a classe EventSource e informamos o endereço para o método Assinar. Uma vez que a ligação estiver estabelecidade, as mensagens começarão a chegar, e vamos capturar essas mensagens através do evento onMessage, fazemos o parse da string transformando-a em JSON e, consequentemente, acessar as propriedades.

<script>
    if (!!window.EventSource) {
        var sse = new EventSource("/api/Noticias/Assinar");

        sse.onmessage = function (e) {
            $('#NovaNoticia').text($.parseJSON(e.data).Titulo);
            $('#AlertaDeNoticia').modal();
        };
    }
</script>

Finalmente, quando o navegador estiver aberto em uma página HTML com o código acima, e uma nova notícia for postada, uma pop-up é aberta exibindo a mesma, assim como é mostrado na imagem acima.

OwinHost.exe

A arquitetura do OWIN está tornando o ambiente de execução de aplicações Web (ASP.NET) muito mais simples e de fácil estensibilidade, sem contar no alívio de performance que ele traz para estes tipos de aplicações, pois está aos poucos tentando diminuir a dependência do assembly System.Web.dll.

Uma das características da arquitetura OWIN é a independência do host onde a aplicação roda. Hoje, quando criamos um projeto no Visual Studio, por padrão, ao pressionar F5, o IIS Express inicia para executar a aplicação para que possam realizar os testes e, principalmente, depurar quando for necessário. O Microsoft OWIN já fornece a implementação de host para rodar a aplicação sobre o pipeline do ASP.NET e uma implementação para self-hosting.

Mas como ele foi criado com a estensibilidade sendo um de seus pilares, a sua API é estensível o suficiente para que se crie novos tipos de hosts. E foi isso que a Microsoft fez para testes de aplicações que são "puramente" OWIN, ou seja, criou uma nova opção para rodar aplicações OWIN no Visual Studio (ou fora dele) que é o OwinHost.exe, e vamos ver sua utilização no decorer deste artigo.

Mesmo utilizando a template Empty do ASP.NET Web Application, o projeto já nasce com a System.Web.dll referenciada e uma porção de outros assemblies que também estão relacionados a ela. Se simplesmente rodarmos a aplicação, o IIS Express entra em ação para hospedar e gerenciar a execução da mesma.

Para os testes, exclui todos estes assemblies e referenciei dois pacotes (via Nuget): Owin e Microsoft.Owin. Depois disso, criei o código abaixo que recebe a requisição e retorna uma simples resposta. Se tentar rodar esta aplicação com esta configuração, não será possível executa-la pois o IIS Express não saberá como lidar com esse tipo de código.

[assembly: OwinStartup(typeof(WebApplication1.Startup))]

namespace WebApplication1
{
    public class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            app.Run(ctx => ctx.Response.WriteAsync("Bem-vindo!"));
        }
    }
}

Se fizermos questão de utilizar o IIS Express (ou IIS), então será necessário a adição de mais um pacote, que é o Microsft.Owin.Host.SystemWeb, que como falei acima, faz com que o OWIN rode sobre o pipeline do ASP.NET. Mas isso não é o que queremos fazer. Ao invés de utilizarmos o IIS, vamos recorrer ao OwinHost, e é este também o nome do pacote disponível via Nuget.

Quando adicionamos este pacote ao projeto, passa a aparecer um novo tipo de host disponível nas configurações do projeto, assim como é mostrado na imagem abaixo. Quando o OwinHost é escolhido entre as opções, algumas configurações específicas são apresentadas, que basicamente determinam a URL e porta onde a aplicação rodará.



Ao rodar a aplicação, o OwinHost.exe se inicia (via console) e o navegador é aberto para que seja possível navegar pela aplicação. E, como podemos notar, isso abrirá as portas para que novos tipos de hosts sejam criados, e independente de qual escolhermos, o Visual Studio evolui para tentar continuar dando a mesma experiência (leia-se facilidade) quando desenvolvemos com ele.

Validade do Cookie no CookieAuthenticationMiddleware

Falei em um outro artigo sobre um componente que temos no OWIN que substitui o Forms Authentication (que é o CookieAuthenticationMiddleware). Como vimos naquele artigo, uma vez que o usuário se identificou como válido para aplicação, este componente é o responsável por emitir o cookie e embutir na resposta; em futuras requisições, o navegador será responsável por encaminhar este cookie, e este mesmo componente fará a validação para saber se o mesmo ainda continua válido.

Por válido me refiro aqui a duas verificações: integridade, que é a garantia que o mesmo não foi alterado entre a ida e a volta e o tempo de expiração. Ambos podem ser configurados através da classe CookieAuthenticationOptions. Só que podemos ter outras coisas que deveriam invalidar o acesso do usuário, como por exemplo, mudanças em seu perfil e/ou a remoção de uma permissão que ele possui(a), e as vezes, por questões de segurança, não podemos esperar até que o cookie expire para renovar as credenciais do usuário.

Apesar deste componente não fazer isso nativamente, ele possui um ponto de estensibilidade que nos permite acoplar um código customizado e fazer esta validação (de forma centralizada). A classe  CookieAuthenticationOptions expõe uma propriedade chamada Provider, que recebe a instância de uma classe do tipo CookieAuthenticationProvider, que por sua vez, possui várias propriedades, que via delegates, conseguimos interceptar e customizar diversos pontos da execução deste componente.

Entre eles, temos a propriedade OnValidateIdentity, que como o nome sugere, nos permite avaliar se a identidade é, ou melhor, continua válida. No exemplo abaixo estamos recorrendo ao gestor de usuários (repositório) e verificando se o mesmo continua sendo válido. Caso não seja, invocamos o método RejectIdentity (que está disponível através do contexto da execução) e obriga o usuário novamente a se identificar para a aplicação, redirecionando-o para a tela de login.

public void Configuration(IAppBuilder app)
{
    app.UseCookieAuthentication(new CookieAuthenticationOptions()
    {
        AuthenticationType = "AppTeste",
        LoginPath = new PathString("/Seguranca/Login"),
        Provider = new CookieAuthenticationProvider()
        {
            OnValidateIdentity = async ctx =>
            {
                if (!(await GestorDeUsuarios.ValidarCadastroDoUsuario(ctx.Identity.Name)))
                    ctx.RejectIdentity();
            }
        }
    });
}

Se quiser tornar a experiência mais amigável para o mesmo, ao invés de utilizar o método RejectIdentity podemos recorrer ao método ReplaceIdentity, gerando uma nova identidade já refletindo as mudanças que foram realizadas na base de dados. O método ValidarCadastroDoUsuario pode fazer a verificação de diversas formas, e entre delas, podemos recorrer à um eventual timestamp que a tabela de usuário possa ter, o que permitirá identificar de forma fácil se alguma informação (coluna) foi alterada..

Utilizando o HTTPS no ASP.NET Web API

Há algum tempo já é possível criar certificados para testarmos em nossas aplicações. Entre os tipos de aplicações que utilizamos certificados, temos aplicações Web (HTML ou APIs) que são expostas através de HTTP e HTTPS. Apesar dos certificados que são considerados "válidos" para o Mercado, devem ser comprados de uma autoridade certificadora (VeriSign, por exemplo), em tempo de desenvolvimento não necessitamos ter todo esse luxo.

Entre as várias opções que temos para criarmos certificados para testes, uma delas é recorrer ao próprio IIS, que possibita a criação de certificados autoassinados, e que podemos perfeitamente utilizar em um ambiente de desenvolvimento. A imagem abaixo ilustra a criação do mesmo e já podemos ver um site configurado com este certificado recém criado.



Se hospedarmos neste site uma Web API, poderemos acessá-la via HTTP ou via HTTPS, afinal, o site dá suporte para estes dois protocolos (bindings). Se quisermos, via programação, forçar com que a requisição seja, obrigatoriamente, realizada através do HTTPS, podemos avaliar antes de executar efetivamente a ação que estão sendo solicitada. Para dar mais flexibilidade, vamos criar um filtro que pode (e deve) ser aplicado naquelas ações que queremos que a mesma esteja sendo acessada através de HTTPS.

public class ValidacaoDeHttps : ActionFilterAttribute
{
    public override void OnActionExecuting(HttpActionContext actionContext)
    {
        var request = actionContext.Request;

        if (request.RequestUri.Scheme != Uri.UriSchemeHttps)
        {
            actionContext.Response =
                request.CreateResponse(
                    HttpStatusCode.Forbidden,
                    new StringContent("É necessário que a requisição seja HTTPS."));
        }
    }
}

Com esta classe criada, podemos decorar as ações que devem ser protegidas pelo transporte. O código abaixo ilustra a utilização deste atributo:

[ValidacaoDeHttps]
public string Get()
{
    return "XPTO";
}

IMPORTANTE: Ao acessar o serviço no navegador, podemos receber um aviso dizendo que o certificado não é confiável. Quando acessamos um recurso via HTTPS, uma das validações que é realizada é identificar se o nome domínio do certificado corresponde ao domínio da URL que estamos acessando. No meu caso, minha máquina chama IsraelAeceNB1; se acessar o serviço como localhost, então um aviso indicando a inconsistência será apresentado. Se utilizar o nome da máquina, então esse aviso não será exibido.

Vale lembrar que esse problema não ocorre somente no navegador. Se estivermos acessando o recurso através do HttpClient, uma exceção será disparada para indicar esse problema. Existe um recurso presente no .NET Framework, que é a possibilidade de interceptar essa validação e, consequentemente, tomar a decisão se podemos ou não aceitar o certificado, mesmo com esta falha. Essa validação deve ser configurada através do delegate ServerCertificateValidationCallback, assim como foi já comentado neste outro artigo.

No exemplo abaixo, estamos acessando o serviço via HTTPS com a URL definida como localhost (o que é suficiente para apresentar o erro), e como estamos dando um by-pass, a requisição é realizada com sucesso. Apesar disso ser útil em um ambiente de testes, é importante dizer que raramente deverá utilizar isso em produção, pois devemos sempre utilizar um "certificado válido".

ServicePointManager.ServerCertificateValidationCallback =
    (sender, certificate, chain, sslPolicyErrors) => true;

using (var client = new HttpClient())
{
    var r = client.GetAsync("https://localhost/api/Informacoes").Result;

    Console.WriteLine(r.StatusCode);
    Console.WriteLine(r.Content.ReadAsStringAsync().Result);
}

Lidando com cookies no WCF

Há algum tempo falei aqui sobre a propriedade AllowCookies dos bindings HTTP e seu funcionamento. Apesar do WCF suportar cookies, era um pouco complicado lidar (gerar e extrair) com eles, ou seja, havia muito código (e não muito intuitivo) a ser escrito para atingir este objetivo.

Como isso é algo comum quando trabalhamos com o protocolo HTTP, então a Microsoft facilitou o acesso aos cookies a partir da versão 4.5 do .NET/WCF. A partir de agora, é possível o cliente lidar diretamente com a classe a CookieContainer, que representa a coleção de cookies e possui um acesso aos mesmos de forma mais simples.

Para acessarmos este novo recurso, podemos recorrer a factory que utilizamos para construir o proxy no cliente, e através da interface IHttpCookieContainerManager chegamos até o CookieContainer. A partir daí, a inclusão e leitura de cookies (gerados pelo servidor) é extremamente simples, assim como podemos visualizar através do código abaixo:

var url = "http://localhost:8272/srv";

using
(var host = new ServiceHost(typeof(Servico)))
{
    host.AddServiceEndpoint(typeof(IContrato), new BasicHttpBinding() { AllowCookies = true }, url);
    host.Open();

    using (var factory =
        new ChannelFactory<IContrato>(
            new BasicHttpBinding() { AllowCookies = true },
            url))
    {
        var proxy = factory.CreateChannel();
        var container = factory.GetProperty<IHttpCookieContainerManager>().CookieContainer;

        //Gerando um Cookie
        container.Add(new Uri(url), new Cookie("Info", "Cliente->Servidor"));

        Console.WriteLine(proxy.Ping("Israel Aece"));

        //Extraindo um Cookie
        Console.WriteLine(container.GetCookies(new Uri(url))[0]);
    }
}

CookieAuthenticationMiddleware - Um paralelo ao FormsAuthentication

Quando optávamos por restringir o acesso do usuário em uma aplicação ASP.NET, tínhamos que recorrer ao Forms Authentication. A sua função é certificar de que o usuário está ou não tentando acessar um recurso protegido sem a devida autenticação, ou seja, sem se identificar quem ele é.

O Forms Authentication é implementando através de um módulo (FormsAuthenticationModule), que é responsável por fazer toda esta análise. Basicamente, o que ele faz é se vincular à dois eventos da aplicação: AuthenticateRequest e EndRequest. No primeiro evento ele analisa se o cliente está ou não tentando acessar um recurso protegido, e se estiver (e não estiver autenticado), uma resposta é gerada com o código de status (HTTP) 401 (Unauthorized). Ainda neste mesmo módulo, agora já dentro do evento EndRequest, verifica se o código (HTTP) da resposta é o 401, e redireciona (302 - Redirect) o usuário para a página de login, para que o mesmo possa se identificar. Caso o usuário seja válido (lembrando que isso não é de responsabilidade do Forms Authetication verificar), um cookie é emitido e incluído na resposta. Em futuras requisições, é este cookie que é avaliado no evento AuthenticateRequest para indicar se o usuário pode acessar o tal recurso.

A partir das versões mais recentes do ASP.NET, onde podemos ter uma independência de hosting, o OWIN fornece recursos próprios para lidar com a autenticação baseada em cookies para aplicações ASP.NET. Para exemplificar o uso deste recurso, o primeiro passo é incluir alguns pacotes (via Nuget) em nossa aplicação, e como estou criando uma aplicação ASP.NET vazia, tive que adicionar todos os recursos que quero utilizar:

  • Microsoft.AspNet.Mvc
  • Microsoft.AspNet.WebPages
  • Microsoft.Web.Infrastructure
  • Owin
  • Microsoft.Owin
  • Microsoft.Owin.Host.SystemWeb
  • Microsoft.Owin.Security
  • Microsoft.Owin.Security.Cookies

Apesar de ASP.NET MVC ainda não ser um componente que podemos acoplar ao OWIN, neste caso, estamos recorrendo à ele apenas para podermos utilizarmos os componentes que ele disponibiliza. Neste caso especificamente, estamos falando o pacote Microsoft.Owin.Security.Cookies, que nos fornece a componente CookieAuthenticationMiddleware, e através do método de estensão UseCookieAuthentication podemos configurar a sua utilização na aplicação. Veja o exemplo a seguir:

[assembly: OwinStartup(typeof(Teste.Startup))]

namespace Teste
{
    public class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            app.UseCookieAuthentication(new CookieAuthenticationOptions()
            {
                AuthenticationType = "AppTeste",
                LoginPath = new PathString("/Seguranca/Login")
            });
        }
    }
}

Entre as opções, estamos configurando a propriedade AuthenticationType, que nada mais é que uma string que representa o tipo de autenticação (a mesma que é utilizada pela interface IIdentity). Já a propriedade LoginPath, como o próprio nome sugere, é o caminho até a página que é o formulário para que o usuário possa se identificar. Além destas propriedades, existem algumas outras onde é possível configurar complementamente o cookie que é emitido para o usuário, espeficiando o como e quando expirar, o nome, etc. Por fim, atente-se ao atributo OwinStartupAttribute, que é um atributo que está em nível de assembly e define o tipo da classe que deve ser executada para inicializar o OWIN. O runtime do ASP.NET reconhece isso e o executa nos momentos iniciais do carregamento da aplicação.

Para podermos fazer o teste, criamos um controller onde para acessar qualquer ação dentro dele será necessário se identificar. Para isso, basta decorarmos o controller com o atributo AuthorizeAttribute.

[Authorize]
public class TesteController : Controller
{
    public ActionResult Index()
    {
        return View();
    }
}

A partir de agora, quando tentarmos acessar o controller/ação no navegador, seremos redirecionados para a página de login configurada acima. Ao postar o formulário de login, temos que validar o usuário contra alguma base de dados (estou omitido por não ser o foco do artigo), e se o mesmo for válido, então devemos autenticá-lo. Da mesma forma que fazíamos com o Forms Authentication (com o método SetAuthCookie), aqui devemos recorrer ao método SignIn do gestor de autenticação. Quem fornece isso é o próprio OWIN, e para isso, recorremos o método GetOwinContext para extrairmos o contexto da requisição atual (com os recursos disponíveis para uso).

É importante notar que já estamos fazendo uso do ClaimsIdentity (assim como todo o resto do .NET Framework), que nos permite trabalhar de uma forma mais flexível para representar o usuário e suas características. Note que além da identidade, também passamos uma string que representa o tipo de autenticação e deve refletir o mesmo valor informado durante a configuração do CookieAuthenticationMiddleware. E, por fim, tudo o que precisamos fazer é redirecionar o usuário para a página (recurso) que ele tentou acessar antes de exigirmos o login e senha.

[HttpPost]
public ActionResult Login(System.Web.Mvc.FormCollection fc)
{
    //Validar usuário em algum repositório

    Request.GetOwinContext().Authentication.SignIn(
        new ClaimsIdentity(
            new[]
    {
        new Claim(ClaimTypes.Name, "Israel"),
        new Claim(ClaimTypes.Email, "ia@israelaece"),
        new Claim(ClaimTypes.Role, "Admin")
    }, "AppTeste"));

    return Redirect(GetRedirectUrl(Request.QueryString["ReturnUrl"]));
}

private string GetRedirectUrl(string returnUrl)
{
    if (string.IsNullOrEmpty(returnUrl) || !Url.IsLocalUrl(returnUrl))
        return Url.Action("Index", "Teste");

    return returnUrl;
}

Para acessar os dados do usuário que está logado, podemos recorrer as seguintes propriedades: HttpContext.User, Page.User (se WebForms) e Thread.CurrentPrincipal que todas retornarão a mesma informação.