domingo, 13 de agosto de 2017

Criando componente reutilizável com JavaScriptResult do .Net MVC

Hoje aprendi: Como utilizar o JavaScriptResult do .Net MVC para entregar javascript no formato de componente

O JavaScriptResult, bem como o ActionResult, são formas de retornar informações através de uma action em um Controller no .Net MVC. Utilizei algumas vezes para algumas aplicações pontuais, até que fui questionado sobre como embedar um código criado por mim, dentro do site de um cliente. Bom, nesse ponto o problema não era como fazer, mas sim, qual a melhor forma dentro do cenário que proposto.

O que eu sabia:

  1. Poderia entregar JavaScript com o JavaScriptResult.
  2. Um componente possui código HTML.
  3. Um componente pode querer se comunicar com uma determinada API e entregar também esses dados "embedados".
  4. Lógicas de negócio necessitariam de resoluções do meu componente.
  5. O cliente precisaria passar parâmetros para meu componente.



Criei uma View que possui todo o código HTML (no _ViewStart removi meu layout, não quero injetar as tags <html><body><head> pois a aplicação cliente já possui) que quero entregar para a aplicação cliente, e no meu controller, duas Actions, uma que retorna minha View (apenas para testar, pois eu pego o html da view diretamente da view que retorna javascript) e outra que retorna um código JavaScript.

A view que retorna JavaScriptResult precisa formatar o html de modo que ele possa ser injetado, como javascript, em uma pagina HTML do cliente. Para isso, criei um método que vai encontrar no HTML cliente a posição onde o meu script foi adicionado. Então, eu coloco o script  que faz a busca pela posição, concatenado com o HTML do meu componente já formatado como string javascript para que seja renderizado corretamente no cliente.

Para fazer a injeção do HTML, usei a função abaixo:


private string Html2Js(string html) {

            return @"

                var scripts = document.getElementsByTagName('script');

                var item;

                for(var i = 0; i < scripts.length; i++)

                {
                    if(scripts[i].src.toLowerCase().indexOf('/boasvindas/ola') > 0)
                        item = scripts[i];
                }
                item.parentElement.insertAdjacentHTML('beforeend', '" + html.Replace("'","\"").Replace(Environment.NewLine, string.Empty) + @"');
            ";
        }

Ah, claro, não posso esquecer de comentar que precisei pegar o html da View e para isso, usei a outra função abaixo:

private string View2String(string vn, object m)
        {
            ViewData.Model = m;
            using (var sw = new StringWriter())
            {
                var result = ViewEngines.Engines.FindPartialView(ControllerContext, vn);
                var viewContext = new ViewContext(ControllerContext, result.View, ViewData, TempData, sw);
                result.View.Render(viewContext, sw);
                result.ViewEngine.ReleaseView(ControllerContext, result.View);

                return sw.GetStringBuilder().ToString();
            }
        }

A controller fica mais ou menos assim:













Claro que é valido retirar da controller e colocar em uma classe a parte as funções Html2Js e View2String.

E para testar esse componente, basta criar um arquivo HTML (simulando um cliente) com o conteúdo:

















<html>
   <head></head>
   <body>
      <h1> Vou carregar o componente logo abaixo: </h1>
      <div>
         <script src="http://localhost:54516/BoasVindas/ola/6"></script>
      </div>
   </body>
</html>


* localhost:54516 é a porta gerado pelo IIS Express.

O Código completo da solução está disponível em: https://github.com/rcelebrone/Componente-JavaScriptResult

quarta-feira, 2 de agosto de 2017

Autorização por token na WebApi

Hoje aprendi: Algumas alternativas com autorização por token na WebApi

O André Baltieri escreveu um artigo simples e bacana com a proposta de demonstrar como configurar uma WebAPI usando Bearer Authentication. Eu costumo usar esse artigo para pegar os pacotes que preciso instalar em um novo projeto WebApi que necessite de autorização via token. Enfim, no que refere-se a geração e utilização do token, entendo observo 4 abordagens. São elas:
  1. Sem nenhum tipo de restrição aos endpoints.
  2. Autorização com geração de token por usuário e senha.
  3. Autorização com geração de token por um "código de cliente"
  4. Autorização controlada por CORS.
1) Não preciso falar nada sobre a primeira abordagem, é basicamente um repositório de operações acessíveis por qualquer requisição, sem restrições. Exemplo: API de consulta de endereço por CEP.

2) A segunda possibilidade seria gerar um token através de um usuário e senha. Exemplo: Etapas de login em aplicativo móvel. Faço uma requisição de um token passando o usuário e senha que o usuário informou, se esses forem validos, gero um token que permite acesso a todos os métodos restritos da API para o aplicativo.

3) A terceira é bem parecida com a segunda, porém o cliente que está utilizando a API, não possui usuário e senha, por talvez não ter uma etapa de login, mas mesmo assim, quero garantir que apenas esse cliente vai usar minha API. Então eu gero um hash qualquer, coloco em algum lugar da aplicação (pode ser no arquivo de configuração) e quando o cliente solicitar o token, ao invés de pegar o usuário e senha, vou pegar o código do cliente (clientId usando a proposta no artigo do André Baltieri) e verificar no meu arquivo de configuração se o hash que estou recebendo no header é igual aos hashs que configurei para ter acesso. Caso o hash tenha acesso, ofereço o token e novamente os métodos restritos terão acesso quando a requisição possuir o token gerado no header.

4) A quarta possibilidade é bem simples também. Caso eu crie um API que será usada pelo domínio xpto.com.br, então basta configurar na própria API para permitir apenas esse domínio. Quando a restrição não é por domínio, geralmente usamos "*" para indicar que qualquer domínio pode ter acesso (e tratamos as restrições com as abordagens 2 e 3 mencionadas acima).


Certo, agora vem a pergunta: Não bastaria eu apenas verificar o usuário e senha ou no caso do código de cliente, comparar o que estou recebendo em cada requisição com o que está no meu arquivo de configuração ao invés de ter de gerar um token ?
A resposta: NÃO. Mas porque ???? :'(

É simples. Se o aplicativo ou site que vai usar minha API recebe um usuário e senha ou um código de cliente, significa que apenas ele deve possuir essa informação. Então, se eu passar esses dados em todas as requisições, ou pior, se esses dados são enviados por javascript por exemplo, estaremos entregando o código do cliente (hash) ou o usuário e senha para qualquer um que seja um pouco curioso (se é um site chamando uma operação via ajax, usando javascript, bastaria usar as ferramentas de desenvolvedor do browser e pronto, teriam acesso para usar a API). Agora, se eu entrego essas chaves, o site faz uma requisição do token (não faça isso via javascript, por favor, fatalmente você irá entregar seus dados. Faça isso no server) e obrigo a geração de token, eu garanto que todas as demais requisições serão autorizadas, e ainda manteremos os dados de usuário e senha ou código de cliente (hash) seguros mesmo quando usado em requisições do tipo GET, ou via javascript (por exemplo), pois o token é gerado de tempo em tempo, sempre muda. 

Vale lembrar que o token é configurado para expirar, então é importante sempre expirar o token pois se alguém, de alguma forma pegar esse token, ele não terá tempo de fazer alguma coisa com ele.

Enfim, é isso :) 


terça-feira, 1 de agosto de 2017

Criando pacote nupkg

Hoje aprendi: Como criar um pacote nupkg a partir de um projeto


Imaginemos um projeto (Class Library) que fornece algum tipo de funcionalidade e usamos a DLL dentro de outros projetos. Isso é comum, porém, quando atualizamos esse Class Library encontramos o problema: Como oferecer essa atualização aos projetos que usam essa DLL ?

A resposta para a pergunta acima é: Criar um pacote nupkg e oferecer em um repositório (pode ser uma pasta local).

Então, como fazer ?
- Faça download do nuget.exe (link para download) e coloque esse executável na sua unidade C:/
- Coloque na raiz do seu projeto (Class Library) um arquivo com a extensão .nuspec (pode ser qualquer nome).
- Coloque o conteúdo abaixo dentro do arquivo .nuspec:
<?xml version="1.0"?><package >  <metadata>    <id>namespace.do.projeto</id>    <version>1.0.0</version>    <authors>Nome do autor</authors>    <owners>Nome do proprietário</owners>    <requireLicenseAcceptance>false</requireLicenseAcceptance>    <description>Descrição do que o projeto se propõe a fazer</description>    <releaseNotes>Informação sobre essa versão</releaseNotes>    <copyright>Copyright 2017</copyright>    <tags>nuspec teste repositório</tags>    <dependencies>      <dependency id="biblioteca.que.minha.class.library.usa" version="1.00" />    </dependencies>  </metadata></package>

- Salve o arquivo e certifique-se de deixar a codificação do arquivo como UTF-8 (assim você evita problemas com acentos).
- Abra o prompt de comando e execute os comandos abaixo:
(em qualquer diretório) cd c:/
(em diretório c:/) nuget.exe pack "C:\pasta\do\seu\projeto\nome.da.solution" 
"C:\pasta\do\seu\projeto\nome.da.solution" (é nesse mesmo diretório que seu arquivo .nuspec deve estar)

- Na unidade C:/ será gerado um arquivo .nupkg, copie esse arquivo e cole no diretório que você quer que seja seu repositório. Por exemplo: "C:/nuget_repo/"
- Coloque o endereço "C:/nuget_repo/" como mais uma fonte de pacotes no nuget (no Nuget Package Manager da sua IDE)