Você está vendo a versão antiga da página. Ver a versão atual.

Comparar com o atual Ver Histórico da Página

« Anterior Versão 40 Próxima »


01. OBJETIVO

Falar sobre a arquitetura do Meu RH no mobile a partir da versão 2.0.0.


02. O QUE USAMOS DO APARELHO?

a) GPS (opcional): Utilizado para obter a localização do usuário quando ele bate o ponto.

b) Câmera (opcional): Utilizado para ler QR Code e tirar foto do atestado/abono.

c) Biometria (opcional): Utilizado na autenticação.


    Para a construção do nosso aplicativo utilizamos o framework de desenvolvimento Ionic na versão 5. Ele é considerado um framework do tipo híbrido, onde temos uma solução web e nativa trabalhando em conjunto. A sua principal característica é a utilização de uma Webview (uma espécie de container) para a renderização dos elementos na tela. Dentre os seus principais benefícios, estão o desenvolvimento mais rápido (utiliza recursos amplamente utilizados no mercado HTML, CSS e Javascript) e trabalhar com multiplataforma (Android e iOS) com apenas um único projeto.


    No projeto do Meu RH utilizamos o Ionic como um projeto full Angular, porém ele permite a integração também com outros frameworks como React, Vue, Stencil, etc. A parte de comunicação para consumir os recursos do celular é feita pelo Cordova, que conta com diversos plug-ins dentre eles a Geolocalização, biometria, câmera, arquivos do celular e outros. O Ionic também conta com uma ampla biblioteca de componentes que podem ser reaproveitados e combinados para criar novas funcionalidades. O projeto está localizado no repositório MeuRH no AzureDevops. 


    A estruturação do nosso app contempla hoje a apenas as páginas relacionadas a login (Login, Esqueceu a Senha, Alterar a senha no primeiro login), a parte de configurações (Configuração de ambiente, Visualização/Compartilhamento de QR-Code, menus de ajuda) e as telas de erros exibidas. Todas as outras funcionalidades do Meu RH são renderizadas pelo projeto de Portais através de um browser que é aberto dentro do aplicativo. Como utilizamos a biblioteca do PO-UI no projeto de Portais e ela é totalmente responsiva, ela adquiri a forma de um aplicativo mobile.

    Porém ao abrir o browser, ficamos com duas webviews diferentes (A própria do Ionic e a outra do browser). Quem acessa os recursos do celular é a própria Webview do Ionic ou o Cordova e por isso o browser onde o portal acessa não tem acesso direto a esses recursos. Porém, sabemos que dentro do aplicativo consumimos esses recursos da mesma forma (Ex: Batida por geolocalização). Para isso funcionar, criamos uma espécie de fila de eventos entre as duas webviews, sendo que sempre quando o portal precisa de algum recurso do celular ele posta uma mensagem na fila de eventos (onde a webview do ionic está sempre escutando), o Ionic solicita o recurso/ação e devolve uma mensagem de resposta para a webview do portal:



    Foi criado um contrato de mensagem nos dois projetos para que os dois lados possam saber o que está sendo solicitado e o que deve ser retornado:

    Projeto de portais solicitando geolocalização:

    Projeto do app recebendo a solicitação e verificando qual o evento recebido:


    Utiliza o plugin do Cordova para recuperar a geolocalização e emite a resposta na fila de eventos para o portal:

    Projeto de portais recebendo a resposta do Ionic. Seta a informação de geolocalização e exibe a localização no mapa renderizado na tela:



    Em relação a comunicação com o backend, o formato se assemelha a versão de Portal do Meu RH, inclusive a parte que ele renderiza o portal pelo browser utiliza todo o mecanismo do projeto de Portais. Porém, algumas API's estão também do lado do Ionic, por exemplo a API de autenticação. Dessa forma, temos um serviço genérico que é capaz de identificar qual o ERP e a partir disso definir qual a url base para realizar as requisições para o backend. A diferença é que agora todas as requisições provenientes do Ionic exigem o mecanismo de CORS (melhor detalhado na sessão de CORS). Dentre as três linhas de produto temos dois tipos de mecanismos, para RM e Protheus utilizamos um Bearer Token e em Datasul utilizamos Basic Authentication (Cookies). Em ambos os mecanismos os objetos de autenticação são compartilhados entre as duas webviews, visto que são necessários nos dois lados:



    Para utilizar a versão atual do aplicativo é necessário que o CORS esteja corretamente configurado, conforme as documentações abaixo:

       - Configuração do CORS no JBOSS

       - Configuração do CORS no TOMCAT

    A autenticação no DATASUL ocorre via cookie.


    É realizado uma requisição POST em /dts/portal-hcm/rest/auth/login. É enviado os dados do usuário via request payload:

    A resposta deverá possuir http status 200 e o seguinte corpo:

    Caso as credenciais estejam incorretas será retornado http status 500 com o seguinte corpo:

    Caso o login tenha acontecido com sucesso é transmitido as credenciais do usuário via mensagem entre a webview do mobile e webview do portal.

    É realizado uma requisição GET em /api/rh/v1/login/auth/[USUARIO]. A autenticação ocorre via basic auth definido pelo frame.

    A resposta deverá possuir http status 200 e o seguinte corpo:

         

    Caso as credenciais estejam incorretas será retornado http status 401 com o corpo vazio.

    Caso o retorno seja status 503:

    É necessário verificar se não há problemas no contexto rest do ambiente. Para isso envie a requisição protocolo://IP:PORTA/api/btb/v1/companies no postman, o retorno deve ser parecido com:

    Se o retorno for 503, o item deve ser analisado pela equipe de framework.


    Login com SSO-FILTER ativo (passando pela página de login do frame): É preenchido automaticamente as credenciais do usuário na página de login do frame. Caso aconteça algum erro de autenticação nessa página a página será exibida para o usuário (ocasionando o que os usuários acreditam ser o bug de login em 2 telas).


    Login com SSO-FILTER desativado: Caso o login tenha acontecido com sucesso é transmitido as credenciais do usuário via mensagem entre a webview do mobile e webview do portal.

    É necessário que o CORS esteja corretamente configurado e utiliza bearer token.

    Desde 09/2021 estamos utilizando nosso aplicativo com o framework Ionic na versão 5. Em relação a versão anterior, tivemos algumas mudanças e as principais delas foram a utilização do mecanismo de CORS, a autenticação por bearer token e a nova forma de comunicação entre o aplicativo e o servidor de aplicação.

    CORS

    Para atender o correto funcionamento do mecanismo de CORS e mantendo a infraestrutura que os clientes já possuíam, estamos utilizando agora o modelo de API's do host disponibilizadas pelo nosso time de framework. Além disso, caso o servidor web utilizado seja IIS, realizar a instalação do módulo adicional de CORS https://www.iis.net/downloads/microsoft/iis-cors-module. Maiores informações sobre o mecanismo de CORS estão na seção relacionada. Para o correto funcionamento do CORS em RM, são necessários 3 cabeçalhos na resposta das requisições de OPTIONS:

    Bearer token

    Outra novidade na versão do Ionic 5 é a utilização do bearer token para autenticação do usuário ao invés do processo de basic authentication. A bearer authentication (também chamada de autenticação por token) é um esquema de autenticação HTTP que envolve tokens de segurança chamados bearer tokens. O nome "Bearer token" pode ser entendido como "dar acesso ao portador deste token". O bearer token é uma string criptografada, gerada pelo servidor em resposta a uma solicitação de login. O client deve enviar este token no cabeçalho de autorização ao fazer solicitações para recursos protegidos. Utilizamos a API Autorização / Autenticação Basic e Bearer Token que retorna um token contendo as informações do usuário e outras claims que são relevantes para ele.

    Como funciona a comunicação entre o IIS e o servidor de aplicação?

    Na versão anterior do aplicativo, utilizavamos a camada de API's do FrameHTML para consumir os serviços necessários. Na nova versão, consumimos as API's que estão na camada do host para recuperar as informações necessárias.


    O endereço de acesso as API's do host é diferente da camada de API's do FrameHTML e não poderíamos realizar alterações de infraestrutura nesse aspecto, pois obrigaria o cliente a gerar novamente o QR Code de ambiente. Dessa forma, estamos utilizando a camada de FrameHTML como uma espécie de client para o host, sendo que todas as requisições ainda são encaminhadas para a camada de FrameHTML e de lá são redirecionadas para o host. Para realizar a comunicação entre a camada FrameHTML e a camada do host são utilizadas as portas de API configuradas dentro dos serviços de host. Para isso, é importante se atentar que caso os servidores de aplicação e de portal sejam separados, não pode haver qualquer tipo de bloqueio sobre as portas de API do host e o servidor de portal deve ser capaz de se comunicar através delas. Para realizar a diferenciação, agora temos 3 controllers que fazem todo o processo.

    O primeiro deles é o controller padrão na camada FrameHTML e que atende o Portal quando utilizamos a autenticação via Cookie. Note que chamamos o server rest diretamente através do método "RetornaListaPermissoesUsuario" nesse caso:

    Ainda na camada FrameHTML, temos o segundo controller. Esse é responsável por atender as requisições de Portal (quando utilizamos autenticação via Token) e o aplicativo com Ionic na versão 5. Ele é responsável por direcionar a requisição para o host através do método "RedirectRequestToNewApiModel". Note que o prefixo dele tem a palavra "new", justamente para segmentar quando deve vir para esse controller ou para o padrão:

    O terceiro controller está na camada do host. Ele é bem similar ao primeiro, porém ja conta com todos os benefícios de estar na camada host. Além disso, ele está atendendo ao redirecionamento realizado pelo segundo controller:

    Para validar o funcionamento do aplicativo na nova versão, foram desenvolvidos dois scripts dentro da ferramenta Postman, que tem como objetivo simular as principais requisições realizadas pelo aplicativo. Um desses scripts simula de fato o comportamento do app, validando o login, CORS e o consumo de serviços em geral (Pode ser executado de qualquer máquina). Já o outro script tem como objetivo consumir algumas das api's que estão dentro do host (Precisa ser executado de dentro da máquina onde exista o serviço de host). O passo-a-passo para executar os scripts estão no documento https://docs.google.com/document/d/1Jr7It3jhl2aUJBpy9T4c7QtxTU51J9SlGLy8JDsQ8PA/edit?usp=sharing. Caso algum teste que seja executado pelo Postman falhe, significa que algum tipo de problema está impedindo o funcionamento correto do aplicativo. Por padrão, todas as API's (exceto a de healthcheck) não retornam informações detalhadas de erro por motivos de segurança. Caso seja necessário obter mais informações para algum tipo de erro nas API's em geral, basta adicionar a tag <add key="ShowCompleteLogErrorMyHr" value="true" /> dentro do Web.config na pasta FrameHTML:

     


    Configurações de ambiente para o Ionic 5

    Pelas especificações de infraestrutura dos clientes, já temos algumas ações mapeadas que podem resolver os problemas de configuração de ambiente. O primeiro passo é seguir os passos descritos no KCS e realizar todas as configurações descritas. Dentre os casos mapeados, temos:

    OBS: Em todos os cenários mapeados, é necessário seguir os passos do KCS. Além disso, a reserva das portas deve ser feita em todos os servidores que possuam serviços ativos de host.


    Portal e biblioteca instalados no mesmo servidor

    Seguir apenas o KCS

    Portal e biblioteca instalados em servidores distintos

    A primeira verificação que deve ser feita é se o servidor de portal consegue "atingir" o servidor de aplicação e como ele faz isso (Através de IP, hostname, DNS, etc). Além disso, é necessário que a comunicação entre o servidor de portal e o de aplicação seja realizada através das portas API configuradas no serviços de host. Caso exista algum mecanismo de segurança entre a comunicação dos dois servidores (firewall, antivírus, proxy, etc) é necessário criar regras para liberar as portas API, caso contrário o aplicativo não irá funcionar. Por padrão o servidor de portal tentará se comunicar com o servidor de aplicação através do hostname. Se não for adequado para a configuração do cliente a utilização do hostname, será necessário adicionar a tag Host dentro dos arquivos RM.Host.Service.exe.config:

    Outras configurações

    Existem algumas configurações que podem ser utilizadas independente de como o cliente organizou sua infraestrutura. Abaixo listamos algumas das que já foram mapeadas.

            WebService - ServicesHostName

    Em casos onde tenha WebService configurado através da tag ServicesHostName no RM.Host.Service.exe.config, a comunicação será feita através do endereço do WebService utilizando as portas de API configuradas no serviço de host.

    OBS: Caso o cliente utilize a tag <add key="EnableWSSecurity" value="true" />, onde habilita a comunicação segura no host, as requisições entre o servidor de portal e o servidor de aplicação utilizaram o protocolo HTTPS. Nesses casos é obrigatória a configuração da tag ServicesHostName pois o domínio precisa ser certificado.

            SubDomainMask ou múltiplas pastas FrameHTML

    Existem casos onde o cliente utiliza apenas um servidor de aplicação que atende a diversos servidores de portal. Ele pode utilizar a configuração de Multi Tenancy(Configurando o RM Multi Tenancy (Multi Alias)) ou replicar diversas pastas FrameHTML apontando para o servidor de aplicação. Nesses casos não se pode utilizar a tag DefaultDB dentro dos serviços de host e sim a tag ServiceAlias dentro do arquivo Web.config na pasta FrameHTML. Além disso, é necessário adicionar a tag <add key="ConsiderServiceAliasMyHr" value="true" /> dentro do arquivo Web.config (Caso existam réplicas da pasta FrameHTML, copiar para todos).

            Clientes que utilizam Proxy Reverso ou mecanismos de encaminhamento

    Caso os cabeçalhos de CORS não estejam sendo repassados corretamente para o client (teste pode ser feito pelo script do Postman), mesmo criando regras de encaminhamento, é necessário fazer uma configuração adicional dentro do IIS. Após realizar a instalação do módulo adicional de CORS https://www.iis.net/downloads/microsoft/iis-cors-module, é necessário adicionar as linhas dentro do web.config dentro da pasta FrameHTML na seção system.webServer

    Configuração CORS IIS
    <system.webServer>
        <cors enabled="true">
            <add origin="http://localhost" allowCredentials="true" maxAge="120">
                <allowHeaders allowAllRequestedHeaders="true">
                    <add header="Content-Type" />
                </allowHeaders>
                <allowMethods>
                    <add method="GET" />
                    <add method="PUT" />
                    <add method="POST" />
                    <add method="OPTIONS" />
                    <add method="DELETE" />
                </allowMethods>
                <exposeHeaders>
                    <add header="Content-Type" />
                </exposeHeaders>
            </add>
            <add origin="ionic://localhost" allowCredentials="true" maxAge="120">
                <allowHeaders allowAllRequestedHeaders="true">
                    <add header="Content-Type" />
                </allowHeaders>
                <allowMethods>
                    <add method="GET" />
                    <add method="PUT" />
                    <add method="POST" />
                    <add method="OPTIONS" />
                    <add method="DELETE" />
                </allowMethods>
                <exposeHeaders>
                    <add header="Content-Type" />
                </exposeHeaders>
            </add>
            <add origin="capacitor://localhost" allowCredentials="true" maxAge="120">
                <allowHeaders allowAllRequestedHeaders="true">
                    <add header="Content-Type" />
                </allowHeaders>
                <allowMethods>
                    <add method="GET" />
                    <add method="PUT" />
                    <add method="POST" />
                    <add method="OPTIONS" />
                    <add method="DELETE" />
                </allowMethods>
                <exposeHeaders>
                    <add header="Content-Type" />
                </exposeHeaders>
            </add>
        </cors>
    </<system.webServer>

    O que é CORS?

    O CORS (Cross-origin Resource Sharing) é um mecanismo utilizado pelos navegadores para compartilhar recursos entre diferentes origens. O CORS é uma especificação do W3C e faz uso de headers do HTTP para informar aos navegadores se determinado recurso pode ser ou não acessado.

    Cross-Origin Resource Sharing (CORS, Compartilhamento de recursos de origem  cruzada) - AWS SDK for JavaScript

    Requisição Preflight

    É necessário sempre verificar se as requisições preflight estão sendo feitas e o retorno deve conter os cabeçalhos necessários de CORS. Por isso, é importante verificar que eles estão sendo retornados de maneira correta e que nenhum tipo de mecanismo de segurança (firewall, antivírus, proxy, etc) estejam barrando os headers.

    Os principais headers de response de CORS são:

    Header Descrição
    Access-Control-Allow-Origin Especifica a origem permitida, podendo ser http://localhost ou * para permitir qualquer uma
    Access-Control-Allow-Methods Métodos que são permitidos para acessar aquele recurso (GET, POST, PUT, DELETE, etc)
    Access-Control-Allow-Headers Quais headers são permitidos na requisição (Headers convencionais e simples já são permitidos)
    Access-Control-Allow-Credentials Se a requisição deve ser feita com credenciais (true ou false)
    Access-Control-Expose-Headers Especifica quais headers o browser pode ter acesso
    Access-Control-Max-Age Tempo de vida do resultado da requisição de OPTIONS


    Os principais headers de request de CORS são:

    Header Descrição
    Origin Especifica a origem do request
    Access-Control-Request-Method Especifica qual o método será usado para requisição seguinte a OPTIONS
    Access-Control-Request-Headers Especifica quais os headers diferentes dos convencionais que serão enviados na requisição


    A requisição de preflight nem sempre é realizada, existem alguns casos que são consideradas como requisições simples. São elas:

    Quando o método é:

    • GET
    • HEAD
    • POST

    E possuir apenas esses headers:

    • Accept
    • Accept-Language
    • Content-Language
    • Content-Type
    • DPR
    • Downlink
    • Save-Data
    • Viewport-Width
    • Width

    E o header Content-Type é:

    • application/x-www-form-urlencoded
    • multipart/form-data
    • text/plain

    E não utilizar ReadableStream ou event listeners em XMLHttpRequestUpload.


    Porém, em outros casos a requisição de preflight é sempre realizada. São eles:

    O método é:

    • PUT
    • DELETE
    • CONNECT
    • OPTIONS
    • TRACE
    • PATCH

    Ou se tiver um header diferente de:

    • Accept
    • Accept-Language
    • Content-Language
    • Content-Type
    • DPR
    • Downlink
    • Save-Data
    • Viewport-Width
    • Width

    Ou se o header Conten-Type tiver um valor diferente dos listados abaixo:

    • application/x-www-form-urlencoded
    • multipart/form-data
    • text/plain

    Ou se utilizar ReadableStream ou event listeners em XMLHttpRequestUpload.

    IONIC e CORS

    Na versão 5 do Ionic todas as requisições qualificadas nos critérios acima, utilizam o mecanismo de CORS. Para isso, os backends devem estar preparados para responder de maneira correta as requisições do tipo OPTIONS. No caso do Ionic temos duas origens diferentes para cada um dos tipos de plataforma, Android e iOS:

    Plataforma Origem
    Android http://localhost
    iOS ionic://localhost


    Para testar se o servidor está com CORS configurado corretamente, basta fazer uma requisição POST/PUT/DELETE em alguma URL da API colocando o Header "Origin" com valor "http://localhost". Por exemplo:


    A resposta do servidor deverá possuir em seu header "Access-Control-Allow-Origin" com "http://localhost".


    Caso o servidor não responda da maneira esperada, o CORS não está configurado corretamente e ocorrerá erros no login do mobile.

    Existem situações onde ocorrem problemas que são intermitentes e/ou temos dificuldades de simular internamente. Como o Meu RH é uma aplicação on premises não temos controle sobre o que é trafegado no ambiente dos clientes. Dessa forma, quando não reproduzimos o problema internamente, temos algumas opções:

    1. Colocar logs no fonte, porém isso gera riscos no ambiente do cliente por ter que adicionar lib/fonte/dll fora da expedição padrão
    2. Debugar no ambiente e máquina do cliente, assim ele consegue adicionar o usuário e senha. Isso funciona apenas no browser, tem limitações que barram algumas threads e causa lentidão extrema no ambiente
    3. Cliente passar ambiente na internet, usuário e senha. Porque isso é necessário:
      1. não é possível criar usuário de testes em ambientes de homologação e produção devido implicações do esocial
      2. certas situações podem ocorrer devido hierarquia na qual o colaborador está inserido
      3. em problemas que ocorrem no app, além dos dispositivos iPhone e Android, é necessário também um aparato para realizar a depuração do projeto (mac, apk de debug, android studio configurado, habilitar depuração usb no android, xCode configurado, conta de desenvolvedor iOS)
    4. Quando o cliente não desejar passar a senha por questões de segurança, utilizar o TOTVS Minha Senha

        




    • Sem rótulos