No vídeo de hoje, vamos demonstrar em como criar uma autenticação de dois fatores no momento de logar no Protheus.
A dúvida de hoje, nos perguntaram, se seria possível criar uma customização que gerasse um token e enviasse para o email do usuário no momento que ele esta fazendo login.
Pensando nisso, montamos um exemplo, onde vamos demonstrar como foi feito usando o ponto de entrada PswSize e a função StartJob.
Segue abaixo o vídeo exemplificando:
E abaixo o código fonte desenvolvido:
//Bibliotecas
#Include "TOTVS.ch"
#Include "TopConn.ch"
/*/{Protheus.doc} User Function PswSize
Efetua a validação do usuário digitado
@type Function
@author Atilio
@since 05/09/2024
@see https://tdn.totvs.com/pages/releaseview.action?pageId=6815189
/*/
User Function PswSize()
Local aRet := PARAMIXB
Local aToken := {.F., ""}
Local cToken := ""
Local cDigitado := ""
//Se não veio via JOB / WS, mostra uma mensagem e veio do SIGAMDI
If ! IsBlind() .And. LjIsMDI()
//Aciona o disparo do eMail e vai gravar o conteúdo dentro de um arquivo
aToken := StartJob("u_zV93Mail", GetEnvServer(), .T., aRet[1])
//Se deu certo o disparo do eMail
If aToken[1]
//Faz a leitura do arquivo e armazena na variável
cToken := MemoRead(aToken[2])
//Apaga o arquivo para prevenir que não haja leitura manual
FErase(aToken[2])
//Faz um laço de repetição infinito
While .T.
//Solicita a digitação do Token
cDigitado := FWInputBox("Insira o Token recebido por eMail: ")
//Se tiver vazio, pergunta se o usuário quer tentar novamente
If Empty(cDigitado)
If FWAlertYesNo("Não foi informado o Token. Você deseja tentar novamente (clique em Sim) ou quer cancelar (clique em Não)?", "Qual opção?")
Loop
Else
Final("Login cancelado pelo usuário")
EndIf
EndIf
//Se bater a informação digitada, encerra o laço
If cDigitado == cToken
Exit
//Senão, mostra mensagem e volta o laço
Else
FWAlertWarning("Token inválido, tente novamente!", "Atenção")
EndIf
EndDo
//Se não, volta pro usuário tentar novamente
Else
FWAlertError("Infelizmente não foi possível gerar o Token de autenticação. Contate o Administrador do Sistema!", "Falha")
aRet := {"", ""}
EndIf
EndIf
Return aRet
/*/{Protheus.doc} User Function zV93Mail
Função que vai disparar o email, foi usada separadamente por causa do RPCSetEnv
@type Function
@author Atilio
@since 05/09/2024
@param cParLogin, Caractere, Login que o usuário inseriu na tela de autenticação
@return aRetorno, Array, Retorna um Array com duas posições sendo [1] Se deu certo o disparo do eMail e [2] nome do arquivo temporário com o token
/*/
User Function zV93Mail(cParLogin)
Local aArea
Local aRetorno := {.F., ""}
Local cEmpAux := "99"
Local cFilAux := "01"
Local cUsrAux := ""
Local cPswAux := ""
Local cQryUsr := ""
Local cParaMail := ""
Local cCorpoMail := ""
Local lOkMail := .F.
Local cArquivo := ""
Local cToken := ""
Local cPasta := "\x_temp\"
//Prepara o ambiente sem usuário mesmo, só para dispararmos eMail
If Select("SX2") == 0
RpcSetEnv(cEmpAux, cFilAux, cUsrAux, cPswAux)
EndIf
aArea := FWGetArea()
//Busca o endereço de eMail do usuário e o código dele
cQryUsr := " SELECT " + CRLF
cQryUsr += " USR_EMAIL, " + CRLF
cQryUsr += " USR_NOME, " + CRLF
cQryUsr += " USR_ID " + CRLF
cQryUsr += " FROM " + CRLF
cQryUsr += " SYS_USR " + CRLF
cQryUsr += " WHERE " + CRLF
cQryUsr += " USR_CODIGO = '" + cParLogin + "' " + CRLF
cQryUsr += " AND D_E_L_E_T_ = ' ' " + CRLF
TCQuery cQryUsr New Alias "QRY_USR"
//Se tiver dados
If ! QRY_USR->(EoF())
//Se a pasta não existir, cria
If ! ExistDir(cPasta)
MakeDir(cPasta)
EndIf
//Se tiver campo eMail preenchido
cParaMail := Alltrim(QRY_USR->USR_EMAIL)
If ! Empty(cParaMail)
//Gera um Token com o Código do usuário, valor randômico da Hora e da Data, depois aplica o Embaralha, e o Encode64
cToken := QRY_USR->USR_ID + RandByTime() + RandByDate()
cToken := Embaralha(cToken, 0)
cToken := Encode64(cToken)
//Pega o próximo alias disponível e define o nome do arquivo dentro de uma pasta da Protheus Data
cArquivo := GetNextAlias()
cArquivo := cPasta + cArquivo + ".txt"
//Realiza o disparo do eMail
cCorpoMail := '<p>Olá <strong>' + QRY_USR->USR_NOME + '</strong>.</p>'
cCorpoMail += '<p>Você tentou acessar o ERP Protheus recentemente né?</p>'
cCorpoMail += '<p>Se sim, seu Token de acesso é: <strong>' + cToken + '</strong></p>'
cCorpoMail += '<p>Se não, entre em contato urgentemente com o email <a href="mailto:contato@atiliosistemas.com">contato@atiliosistemas.com</a>.</p>'
cCorpoMail += '<p>Um grande abraço.</p>'
lOkMail := GPEMail("Protheus - Token Temporário", cCorpoMail, cParaMail, /*aAnexos*/, /*lExibeHelp*/)
//Se deu certo o disparo do email, define o retorno e grava num arquivo para leitura posterior
If lOkMail
aRetorno[1] := .T.
aRetorno[2] := cArquivo
//Grava o token no arquivo
MemoWrite(cArquivo, cToken)
EndIf
EndIf
EndIf
QRY_USR->(DbCloseArea())
FWRestArea(aArea)
Return aRetorno
Bom pessoal, por hoje é só.
Abraços e até a próxima.