Acesso via Link

Bom dia,
Tenho uma aplicação q o cliente pode acessar uma página dela se for solicitado, mas não quero deixar ela aberta e não quero fazer um uma tela de login e senha.
Queria acessar está aplicação de tela única via link, seria gerar um link de acesso com um código e mandar para o cliente, depois se precisar posso desativar o acesso do cliente eu faço.
Teria como fazer isso?

É possível fazer uma verificação no onApplicationInit com algo assim:

if (isset($_GET['myParam']) && $_GET['myParam'] == 'CodigoCliente') {
   die('acesso incorreto');
}

Essa validação vai garantir que o parâmetro myParam seja necessário e que tenha o valor CodigoCliente para funcionar. Também é possível que você faça uma validação no banco com o valor dado pra o cliente. Tendo uma tabela com as colunas de id, cliente, codigo, validade e ativo. Essas colunas possibilitariam alguns benefícios:

  • Permitir ou negar acesso para cada cliente/código criado. O mesmo cliente pode ter mais de um código.
  • Definir data de validade para cada código.
  • Rastrear acesso e saber qual cliente acessou a aplicação em determinado momento.
  • Saber de onde se originou o link caso ocorra algum vazamento/compartilhamento.
  • Saber se houve tentativa de acesso com link expirado ou desativado.

A validação no banco ficaria parecida com a anterior, com algumas mudanças:

if (isset($_GET['myParam'])) {
   die('acesso incorreto');
} else {
   $cod = sc_sql_injection($_GET['myParam']);
   sc_lookup(ds, "SELECT cliente FROM my_table WHERE codigo = '".$cod."' AND ativo = 1 AND validade > NOW()");
   $dataset = {ds};
   if (!isset($dataset) || empty($dataset)) {
      die('Código desativado ou expirado');
   }
}

A partir dessas linhas, você terá acesso ao nome do cliente em $dataset[0][0] para fins de log. Lembre-se de que a coluna codigo não pode ter valores repetidos na base.


Seria isso?

A ideia é liberar o acesso por tempo determinado, por isso não seria uma melhor opção, mas obrigado pela interação

Obrigado pela dica, vou vê preparar aki

Tenho uma aplicação de formulário que faz algo parecido.

O cliente acessa sem precisar logar em nada.

A mágica acontece quando passo o link para ao cliente passando um parâmetro junto. No caso passo um token aleatório gerado específico para o cliente. Somente atráves do link do e-mail, o cliente consegue acessar esse formulário. No meu sistema, o cliente inclusive consegue editar as informações após uma inclusão.

Exemplo do link gerado automático.

seulink.com/formulario/?formulario_id=$idFormulario&token=$token

Neste sistema, o cliente tem 3 dias para preencher o formulário antes que o mesmo bloqueie o acesso de maneira automática. Nesta parte, utilizo o cron para fazer ele rodar um SQL onde verifica quais formulários serão fechados naquele dia e muda o status do formulário para encerrado. Quando encerrado, redireciona para uma tela avisando que o formulário foi encerrado e não é possível mais realizar uma alteração.

O que faço é parecido com o que o @HenriqueB fez ali em cima, porém de maneira personalizada.

Já estudou JWT?

É a forma mais segura de fazer o que deseja.

Você determina o tempo de expiração do link.

URL completamente ilegível.

eu desenvolvi uma classe para facilitar o uso do JWT.

<?php

namespace Actions;

class IWJwt
{
    private $header = ['typ' => 'JWT', 'alg' => 'HS256'];
    private $payload;
    private $key;
    private $date;
    private $hash = ['HS256' => 'sha256'];

    public function __construct($key = '')
    {
        if (empty($key)) {
            $this->key = $this->createSecretKey();
        } else {
            $this->key = $key;
        }
        $this->date = new \DateTime();
        $this->payload['expire'] = $this->date->add(new \DateInterval("PT5M"));
    }

    public function createSecretKey()
    {
        $dt = new \DateTime();
        $this->key = $dt->format('d*y@m');
        return $this->key;
    }

    public function setKey($key)
    {
        $this->key = $key;
    }

    public function setType($value)
    {
        $this->header['typ'] = $value;
    }

    public function setHash($value)
    {
        $this->header['alg'] = $value;
    }

    public function setPayLoad($item)
    {
        foreach ($item as $key => $value) {
            $this->payload[$key] = $value;
        }
    }

    public function setExpire($time)
    {
        $this->payload['expire'] = $this->date->add(new \DateInterval("P$time"));
    }

    public function encode()
    {
        $header = json_encode($this->header);
        $header = base64_encode($header);
        $payload = json_encode($this->payload);
        $payload = base64_encode($payload);
        $signature = hash_hmac($this->hash[$this->header['alg']], "$header.$payload", $this->key, true);
        $signature = base64_encode($signature);
        $token = "{$header}.{$payload}.{$signature}";
        return base64_encode($token);
    }

    public function decode($token, $key = '')
    {
        $token = base64_decode($token);

        if (!$key) {
            $key = $this->key;
        }

        $token = explode('.', $token);

        $header = json_decode(base64_decode($token[0]), true);
        $payload = json_decode(base64_decode($token[1]), true);
        $hash = $this->hash[$header['alg']];
        $checkedSignature = hash_hmac($hash, "$token[0].$token[1]", $key, true);
        $signature = base64_decode($token[2]);

        if ($checkedSignature != $signature) {
            return '999';
        }

        $date = new \DateTime();
        $expire = new \DateTime($payload['expire']['date']);

        echo $date->getTimestamp(), '>',  $expire->getTimestamp(), PHP_EOL;

        //echo $expire->format('H:i:s'), PHP_EOL;

        if ($date->getTimestamp() > $expire->getTimestamp()) {
            return '998';
        }

        return $payload;
    }

    public function getPayLoad($token)
    {
        $token = base64_decode($token);
        $token = explode('.', $token);
        $payload = json_decode(base64_decode($token[1]), true);
        return $payload;
    }

    public function echo()
    {
        echo '<pre>', print_r($this->payload, 1), '</pre>';
    }
}

Achei que JWT servia apenas como substituto para sessão, baseada em token via header da requisição. Pra isso, eu imagino que deve haver uma tela para geração do token (por exemplo, uma tela de login). Como funcionaria o JWT pra ser compartilhado via link direto?

A explicação IWMaster mais minha classe explicam bem.