[Vraptor 3] Uso de Interceptors para Auditoria

3 respostas
rodrigousp

Estou documentando uma solução de auditoria que desenvolvemos aqui com uma ajuda do Lucas.
No site do VRaptor existe um exemplo sobre como utilizar os interceptadores como Log.

O problema é que no mundo real não basta logar o que está sendo chamado. É preciso saber quem está fazendo a ação, verificar se essa pessoa tem permissão para realizar a ação requerida e registrar o que ela está fazendo (método e parâmetros). Para isso, criamos dois interceptadores, SecurityInterceptor e o AuditInterceptor.

A solução que aqui propomos permite o uso de balanceamento por Round Hobin entre servidores WEB ao manter a sessão centralizada numa base de dados.

Recuperamos do Cookies HTTP, no SecurityInterceptor, uma chave de segurança gerada no momento do login.

String sessionId = getSessionIdFromCookies();

O registro da sessão é procurada na base local que mantém todas sessões ativas (a chave primária é o sessionId). Esse valor sessionId é mantido no cookie do navegador e sempre que uma requisição é feita a chave também é enviada.

Uma vez que a sessão é validada, os valores da sessão (que estavam na base) são guardados num objeto de requisição para serem usados nos passos seguintes a autorização (ex: auditoria e a execução em si do método). Para isso utilizamos um SessionWrapper.

@Component
@RequestScoped
public class SessionWrapper {

	private Session session;
	
	public Session getSession() {
		return session;
	}

	public void setSession(Session session) {
		this.session = session;
	}
}

Temos então que o AuditInterceptor deve ser executado após o SecurityInterceptor. Isso é feito com uso com a anotação @Intercepts(after = SecurityInterceptor.class).
Como precisamos saber quais os parâmetros são utilizados no log, colocamos o MethodInfo no constructor do AuditInterceptor. Abaixo, segue a snippet da implementação do Interceptor.

public AuditInterceptor(SessionWrapper sessionWrapper, MethodInfo methodInfo, MutableRequest request) {
		this.sessionWrapper = sessionWrapper;
		this.request = request;
		this.methodInfo = methodInfo;
	}

	@Override
	public void intercept(InterceptorStack stack, ResourceMethod method, Object resourceInstance) throws InterceptionException {
		String usuario;
		if (sessionWrapper.getSession() == null) {
			usuario = "*** DESCONHECIDO ***";
		} else {
			usuario = sessionWrapper.getSession().getUser().getLogin();
		}
		String methodName = method.getMethod().getName();
		StringBuffer url = request.getRequestURL();

		Object[] objects = methodInfo.getParameters();

		LOGGER.info("Usuário \"" + usuario + "\" acessou \"" + methodName + "\" URL: " + url + " Parametros: " + parametersToString(objects));
		stack.next(method, resourceInstance);
	}

Existe uma oportunidade de melhoria nesse ponto. Os parâmetros chegam ao servidor inicialmente como String são convertidos para Objeto. Agora, nesse ponto convertemos novamente para String. Recuperando os valores originais da requisição teremos uma utilização mais racional de recursos.

Agora, nos deparamos com outro problema. Nossos Controllers guardam a sessão do usuário diretamente (uma vez que não faz sentido para eles guardarem o SessionController). No construtor desses controllers invocamos o método getSession do SesisonWrapper. Para garantir que o SessionWrapper terminou de ser carregado, Adicionamos a anotação o parâmetro (before=InstantiateInterceptor.class) em nossos interceptadores.

E ai está…

@Intercepts(after = SecurityInterceptor.class, before=InstantiateInterceptor.class)
public class AuditInterceptor implements Interceptor{
...
}

@Intercepts(after=ParametersInstantiatorInterceptor.class, before=InstantiateInterceptor.class )
public class SecurityInterceptor implements Interceptor {
...
}

3 Respostas

L

Explica melhor essa parte de manter a sessão. Você vai disponibilizar esses interceptors?

rodrigousp

Num posso.
Explicação melhor. Como eu poderia explicar melhor?

Para manter a sessão: ao fazer login o sistema faz um insert na base. Gera um UUID como chave, devolve o UUID para o usuário. Esse é mantido no cookie.
Quando o usuário desloga o registro é removido. O Registro tem um tempo de duração e uma data de última atividade… Essa data de atividade pode ser atualizada.

[]'s
Rodrigo

L

Com essa tua abordagem é possível que em um servidor com várias apps, um usuário faça apenas um login para acessar qualquer uma dessas aplicações?
Como o google faz com o gmail, orkut, google docs.

Criado 26 de maio de 2011
Ultima resposta 26 de mai. de 2011
Respostas 3
Participantes 2