Existem situações em que, estando em um sistema, é necessário buscar um recurso em outro sistema sem a necessidade de permanecer logado neste. Podemos citar como exemplo, a busca de históricos de discentes no SIGAA pelo módulo de bolsas do SIPAC. Nesse caso, precisamos autenticar no SIGAA apenas para buscar o histórico. Assim que obtivermos o histórico, não é mais necessário nenhum vínculo com o SIGAA.
Para esses casos, foi criado um esquema de autenticação por token. Através dele, quando vamos buscar um recurso em outro sistema, podemos criar um token no sistema de origem e, quando o recurso é acessado no sistema de destino, invalidamos o token. A criação e utilização de tokens utiliza duas classes da arquitetura: TokenAutenticacao
e TokenUtil
. A classe TokenAutenticacao
é a classe de domínio que contém as informações do token. Ela é gerada a partir da classe TokenUtil
, que possui o método generateToken
. As informações do token são armazenadas na tabela token_autenticacao, do banco comum.
Podemos ver nas listagens abaixo, informações relativas à classe TokenAutenticacao
, TokenUtil
e o ddl de criação da tabela no banco de dados.
public class TokenAutenticacao { /** Chave do token. */ private String key; /** Data de criação do token. */ private Date data; /** Registro de entrada do usuário que criou o token. */ private RegistroEntrada entrada; /** Sistema de origem do usuário que criou o token. */ private Sistema origem; /** Se o token já foi usado ou não. Se já tiver sido usado, é inválido. */ private boolean valido; // Getters e Setters
public class TokenUtil { /** * Cria um token, gerando sua chave com base nas informações passadas * como parâmetro e inserindo-o no banco de dados. */ public static TokenAutenticacao generateToken(UsuarioGeral usuario, int sistema, String... info) { // ... } /** * Invalida o token, ou seja, diz que o token já foi usado uma vez e não * pode ser mais usado. */ public static void invalidateToken(int sistema, String key) { // ... }
CREATE TABLE token_autenticacao ( "key" CHARACTER VARYING(255), valido BOOLEAN, id_sistema_origem INTEGER, DATA TIMESTAMP WITHOUT TIME zone, id_registro_entrada INTEGER, CONSTRAINT token_autenticacao_id_sistema_origem_fkey FOREIGN KEY (id_sistema_origem) REFERENCES sistema (id) MATCH SIMPLE ON UPDATE NO ACTION ON DELETE NO ACTION ) WITH ( OIDS=FALSE ); ALTER TABLE token_autenticacao OWNER TO comum_user; COMMENT ON TABLE token_autenticacao IS 'Representa um token Single Sign On que permite que um usuário acesse um recurso existente em outro sistema sem a necessidade de efetuar logon.'; COMMENT ON COLUMN token_autenticacao."key" IS 'Chave do token.'; COMMENT ON COLUMN token_autenticacao.valido IS 'Se o token já foi usado ou não. Se já tiver sido usado, é inválido.'; COMMENT ON COLUMN token_autenticacao.id_sistema_origem IS 'Sistema de origem do usuário que criou o token.'; COMMENT ON COLUMN token_autenticacao.data IS 'Data de criação do token.'; COMMENT ON COLUMN token_autenticacao.id_registro_entrada IS 'Registro de entrada do usuário que criou o token.';
Para criar um token, precisamos chamar o método generateToken
, da classe TokenUtil. Devemos passar para esse método o usuário logado, o sistema de origem e um conjunto de informações sobre o recurso que desejamos acessar que, juntos, formarão a chave do token. O método irá nos retornar um objeto do tipo TokenAutenticacao
. Em seguida, redirecionamos para a URL do sistema de destino que irá nos fornecer o recurso, passando como parâmetros de request o sistema de origem e a chave do token. Um exemplo de geração de token pode ser visto no código abaixo.
TokenAutenticacao key = TokenUtil.generateToken(getUsuarioLogado(req), getSistema(req), matricula); res.sendRedirect("/sigaa/public/historicoExterno.do?usuario=" + getUsuarioLogado(req).getId() + "&matricula=" + matricula + "&sistema=" + Sistema.SIPAC + "&key=" + key.getKey());
Após gerar um token, redirecionamos o usuário para a URL relativa ao recurso que se deseja acessar. No controller associado a essa URL, devemos verificar se o token enviado através da URL é válido. Podemos realizar essa operação através do método isTokenValid(), de TokenUtil
. Se o token for válido, devemos invalidar o token, para prevenir que outras pessoas acessem o recurso de forma indevida. Invalidamos um token através do método invalidateToken(), de TokenUtil
. Se o token não for válido, deverá ser mostrada ao usuário uma mensagem de erro informando que o token foi expirado e que não pode mais ser utilizado.
String key = req.getParameter("key"); int sistema = Integer.parseInt(req.getParameter("sistema")); if (TokenUtil.isTokenValid(sistema, key)) { TokenUtil.invalidateToken(sistema, key); // Acesso a recursos } else { // Erro: token expirado }