Caelum java-web-fj28 Web 2.0 com VRaptor, Hibernate e Ajax - Roles

Ola pessoal do forum, estou aqui quebrando a cabeça para tentar resolver a parte de permissões da apostila. Ele esta funcionando com uma permisão unica, se existe o Role ele acessa se não existe o Role, não acessa

Seguinte, tenho as seguintes paginas:

Role.jsp

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Role {
       String value();
}

Autorizadorintercept.java

public class AutorizadorInterceptor implements Interceptor {

	@In(scope=ScopeType.SESSION, required=false)
	private Usuario usuario;
	
	public void intercept(LogicFlow flow) throws LogicException, ViewException {
		// pega request e response
		HttpServletRequest request = flow.getLogicRequest().getRequest();
		HttpServletResponse response = flow.getLogicRequest().getResponse();
		
		try {
			// usuario nao esta logado
			if (this.usuario == null) {
				// redireciona pro login
				response.sendRedirect("admin.login.logic");
			}else{ // usuario esta logado
				//pega anotacao @Role no metodo da logica
				Role role = flow.getLogicRequest().getLogicDefinition()
				.getLogicMethod().getMetadata().getAnnotation(Role.class);
				
				// tem role definido
				if (role != null) {
					// se usuario tem o role pedido, executa
					if (this.usuario.hasRole(role.value())) {
						flow.execute();
					} else {
						// sem permissao, vai pra admin.semrole.logic
						request.getRequestDispatcher("semrole.jsp").forward(request, response);
					}
				} else {
					//nao tem role, entao pode executar
					flow.execute();
				}
			}
		} catch (Exception e) {
			throw new LogicException(e);
		}
	}
}

UsuarioLogic.java

//adiciona um usuario
	@Role("admin")
	public void adiciona(Usuario usuario) {
		// ... logica de adicionar no banco aqui...
		this.daoFactory.beginTransaction();
		this.daoFactory.getUsuarioDao().adiciona(usuario);
		this.daoFactory.commit();
		//System.out.println("Adiciona usuario");
	}
	
	//remove um Usuario
	@Role("admin")
	public void remove(Usuario usuario) {
		this.daoFactory.beginTransaction();
		this.daoFactory.getUsuarioDao().remove(usuario);
		this.daoFactory.commit();
	}

Como fazer sua anotação aceitar mais de um Role para o mesmo método?

Role.jsp

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Role {
       String[] value();
}

E usar esses valores nos métodos assim:

UsuarioLogig.java

//adiciona um usuario
	@Role({"admin", "operador"})
	public void adiciona(Usuario usuario) {
		// ... logica de adicionar no banco aqui...
		this.daoFactory.beginTransaction();
		this.daoFactory.getUsuarioDao().adiciona(usuario);
		this.daoFactory.commit();
		//System.out.println("Adiciona usuario");
	}
	
	//remove um Usuario
	@Role({"admin", "operador"})
	public void remove(Usuario usuario) {
		this.daoFactory.beginTransaction();
		this.daoFactory.getUsuarioDao().remove(usuario);
		this.daoFactory.commit();
	}

Como posso mudar o Autorizadorintercept.java para aceitar essas novas permissões?

Aguardo um help.

faz um foreach em role.value() na linha 24 do AuthorizationInterceptor…

for(String roles : role.value()) {

}

vc já pensou em usar o VRaptor3? Baixe a apostila nova:
http://www.caelum.com.br/curso/fj-28-vraptor-hibernate-ajax/

E ai Lucas, fiz o seguinte:

no AuthorizationInterceptor.java

public class AutorizadorInterceptor implements Interceptor {

	@In(scope=ScopeType.SESSION, required=false)
	private Usuario usuario;
	
	public void intercept(LogicFlow flow) throws LogicException, ViewException {
		// pega request e response
		HttpServletRequest request = flow.getLogicRequest().getRequest();
		HttpServletResponse response = flow.getLogicRequest().getResponse();
		
		try {
			// usuario nao esta logado
			if (this.usuario == null) {
				// redireciona pro login
				response.sendRedirect("admin.login.logic");
			}else{ // usuario esta logado
				//pega anotacao @Role no metodo da logica
				Role role = flow.getLogicRequest().getLogicDefinition()
				.getLogicMethod().getMetadata().getAnnotation(Role.class);
				
				// tem role definido
				if (role != null) {
					for(String roles : role.value()) {
					// se usuario tem o role pedido, executa
						if (this.usuario.hasRole(role.value())) {
							flow.execute();
						} else {
							// sem permissao, vai pra admin.semrole.logic
							request.getRequestDispatcher("semrole.jsp").forward(request, response);
						}
					}
				} else {
					//nao tem role, entao pode executar
					flow.execute();
				}
			}
		} catch (Exception e) {
			throw new LogicException(e);
		}
	}
}

O UsuarioLogic.java era assim

        //remove um Usuario
	@Role("admin")
	public void remove(Usuario usuario) {
		this.daoFactory.beginTransaction();
		this.daoFactory.getUsuarioDao().remove(usuario);
		this.daoFactory.commit();
	}

        //formulario para adicao
        @Role("admin")
	public void formulario() {
		
	}
	
	//validaçao para arquivo de remessa
        @Role("admin")
	public void remessa() {
		
	}

e agora estão assim:

        //remove um Usuario
	@Role({"admin","operador"})
        public void remove(Usuario usuario) {
  		this.daoFactory.beginTransaction();
		this.daoFactory.getUsuarioDao().remove(usuario);
		this.daoFactory.commit();
	}

	//formulario para adicao
	@Role({"admin","operador"})
	public void formulario() {
		
	}
	
	//validaçao para arquivo de remessa
	@Role({"admin","operador"})
	public void remessa() {
		
	}

no cadastro de Usuarios exeste 3 tipos de permissões 1-amin, 2-operador e 3-visualizados, queria o seguinte:

Admin - faz tudo;
Operador - lista e cadastra;
Visualizador - só lista;

E agora que fiz isso, no Formulario, por exemplo, não consigo vizualizar nada, como se estivesse sem permissão.
O que sera que eu fiz de errado?

linha 25 do interceptor… troca o role.value() por roles

Me diga uma coisa Lucas, eu posso colocar quantas Roles que eu quizer? Dessa forma que você me disse para fazer?

//adiciona um usuario
	@Role("admin")
	public void adiciona(Usuario usuario) {
		// ... logica de adicionar no banco aqui...
		this.daoFactory.beginTransaction();
		this.daoFactory.getUsuarioDao().adiciona(usuario);
		this.daoFactory.commit();
		//System.out.println("Adiciona usuario");
	}
	
	//remove um Usuario
	@Role("admin")
	public void remove(Usuario usuario) {
		this.daoFactory.beginTransaction();
		this.daoFactory.getUsuarioDao().remove(usuario);
		this.daoFactory.commit();
	}
	
	//formulario para adicao
	//@Role("admin")
	@Role({"admin","operador"})
	public void formulario() {
		
	}
	
	//validaçao para arquivo de remessa
	@Role({"admin","operador","vizualizador"})
	public void remessa() {
		
	}
	
	//ferramentas para servidores
	@Role({"operador","vizualizador"})
	public void ferramentas() {
		
	}
	
	//agendamentos dia caixa
	@Role({"admin","vizualizador"})
	public void agendacaixa() {
		
	}
	
	//Clientes da TJT Tec
	@Role({"admin","vizualizador"})
	public void formulariodatjt() {
		
	}
	
	//formulario para edicao
	@Role("admin")
	public void editar(Usuario usuario) {
		//carrega os dados no banco para edicao
		this.usuario = this.daoFactory.getUsuarioDao().procura(usuario.getIdusuario());
	}

Se eu fizer como esta no Metodo Ferramentas, com os usuarios que tem uma das roles, ele esta me dizendo que esta sem permissão, mais quando eu logo no site com o Role admin funciona com o vizualizador e com operador não esta funcionando.

Pode me ajudar?

vai no interceptor…

vc tem uma lista de roles (role.value())

se o cara tiver uma das roles dessa lista, vc dá um flow.execute()
senão, vc redireciona o cara pra página de login (dá a exception)

tenta fazer isso sozinho… aí vai funcionar pra todas as roles

Eu não sei seu sou eu que estou meio besta, mais da forma que vc me passou só esta funcionando com o usuario que tem a Role admin, quando eu uso os outros usuarios 1 que tem operador e 1 que tem visualizador, não esta funcionando. E ainda não intendi pq?

separa isso:


#  for(String roles : role.value()) {  
#                     // se usuario tem o role pedido, executa  
#                         if (this.usuario.hasRole(role.value())) {  
#                             flow.execute();  
#                         } else {  
#                             // sem permissao, vai pra admin.semrole.logic  
#                             request.getRequestDispatcher("semrole.jsp").forward(request, response);  
#                         }  
#                     }  

num método que retorna true se o cara tem uma das roles, e false caso contrario daí vc substitui esse if this.usuario.hasRole() por esse método que vc extraiu

So para fazer um teste rapido, fiz o seguinte:

if (role != null) {
					for(String roles : role.value()) {
					// se usuario tem o role pedido, executa
						if (this.usuario.hasRole(roles)) {
							System.out.println("True - Tem permissão");
							flow.execute();
						} else {
							// sem permissao, vai pra admin.semrole.logic
							System.out.println("Falso - Não tem permissão");
							request.getRequestDispatcher("semrole.jsp").forward(request, response);
						}
					}
				} else {
					//nao tem role, entao pode executar
					flow.execute();
				}

Quando eu clico para buscar o metodo abaixo

//ferramentas para servidores
	@Role({"admin","visualizador"})
	public void ferramentas() {
		
	}

23:54:29,049 DEBUG TwoPhaseLoad:130 - resolving associations for [br.com.tjttecnologia.modelo.Usuario#13]
23:54:29,049 DEBUG TwoPhaseLoad:226 - done materializing entity [br.com.tjttecnologia.modelo.Usuario#13]
23:54:29,050 DEBUG TwoPhaseLoad:130 - resolving associations for [br.com.tjttecnologia.modelo.Usuario#14]
23:54:29,051 DEBUG TwoPhaseLoad:226 - done materializing entity [br.com.tjttecnologia.modelo.Usuario#14]
23:54:29,052 DEBUG TwoPhaseLoad:130 - resolving associations for [br.com.tjttecnologia.modelo.Usuario#20]
23:54:29,052 DEBUG TwoPhaseLoad:226 - done materializing entity [br.com.tjttecnologia.modelo.Usuario#20]
23:54:29,053 DEBUG StatefulPersistenceContext:860 - initializing non-lazy collections
23:54:29,054 DEBUG ConnectionManager:427 - aggressively releasing JDBC connection
23:54:29,055 DEBUG ConnectionManager:464 - releasing JDBC connection [ (open PreparedStatements: 0, globally: 0) (open ResultSets: 0, globally: 0)]
23:54:29,354 WARN ExportViewFactory:105 - Unable to instantiate class for pdf export. org.displaytag.export.PdfView was found, but required libraries are missing: com/lowagie/text/Element
Falso - Não tem permissão <—
True - Tem permissão <—
23:54:31,171 DEBUG SessionImpl:247 - opened session at timestamp: 12706088711

Ele vai validar primeiro o Falso, correto?

tenta simular o que está acontendo e tenta pensar no que vc quer fazer…

isso é algo básico de programação, vc precisa saber… não vou te dar a resposta…

Beleza, vou fazer o seguinte, primeiramente vou dormir um pouco para poder pensar melhor, amanha eu te dou a resposta.

Mais muito obrigado pela força.

Cara consegui fazer funcionar, mais não sei se esta correto o que eu fiz, segue abaixo:

if (role != null) {
					for(String roles : role.value()) {
					// se usuario tem o role pedido, executa
						if (this.usuario.hasRole(roles)) {
							//System.out.println("True - Tem permissão");
							flow.execute();
						} 
					}
					request.getRequestDispatcher("semrole.jsp").forward(request, response);
				} else {
					//nao tem role, entao pode executar
					flow.execute();
				}

não está correto…

do jeito que está, o flow.execute() pode ser executado mais de uma vez (se o usuário tiver 2 roles da lista, por exemplo) e o request…forward() vai ser executado sempre…

o que vc precisa é executar o flow.execute() uma única vez, se o usuario não tiver a role, e só executar o forward se o usuário não tiver nenhuma role da lista

Então o correto é fazer o seguinte:

if (role != null) {
	for(String roles : role.value()) {
	// se usuario tem o role pedido, executa
		if (this.usuario.hasRole(roles)) {
			//System.out.println("True - Tem permissão");
			flow.execute();
		} 
	}
	} else {
		//nao tem role, entao pode executar
		//flow.execute();
                request.getRequestDispatcher("semrole.jsp").forward(request, response);
	}

tb não…

vê se esse método não te ajuda:

public boolean temRole(String[] roles) {
# for(String role : roles) {  
#     // se usuario tem o role pedido, executa  
#         if (this.usuario.hasRole(role)) {  
#             return true
#         }   
#     }  
    return false;
}

Dae Lucas, cara eu ja te agradeço adiantado pela força que esta me danso.

Sobre o que estavamos validando, segue abaixo o AutorizadorInterceptor.java e ele esta funcionando certinho:

try {
			// usuario nao esta logado
			if (this.usuario == null) {
				// redireciona pro login
				response.sendRedirect("admin.login.logic");
			}else{ // usuario esta logado
				//pega anotacao @Role no metodo da logica
				Role role = flow.getLogicRequest().getLogicDefinition()
				.getLogicMethod().getMetadata().getAnnotation(Role.class);
				// tem role definido
				if (role != null) {
					for(String roles : role.value()) {
					// se usuario tem o role pedido, executa
						if (this.usuario.hasRole(roles)) {
							flow.execute();
						} 
					}
					request.getRequestDispatcher("semrole.jsp").forward(request, response);
				} else {
					//nao tem role, entao pode executar
					flow.execute();
				}
			}
		} catch (Exception e) {
			throw new LogicException(e);
		}