Minha contribuição - Controle de acesso VRaptor 3

Alias bronx onde posso baixar seu jar?? Não achei um link pra dar uma olhada e brincar um pouco nele.

Eu estava passeando por aqui, e ressuscitando o tópico… o projeto do Bronx ficou muito bom. Lucas, não dá para criar lá no site do vraptor uma espécie de “área de plugins de fãs do vraptor” e disponibilizar esses pequenos projetos? Achei que se o peão procurar aqui nos tópicos fica complicado achar as informações corretas entre 5 páginas com posts bem estensos.

Pensei em uma página onde tenha uma lista dessas coisas, e talvez os docs e link para download.

Abraços

garcia-jj Eu fiz isso com a Loja Virtual do VRAptor 2

       Acho que o Paulo deve Fazer isso !

jr

[quote=juniorsatanas]garcia-jj Eu fiz isso com a Loja Virtual do VRAptor 2

       Acho que o Paulo deve Fazer isso !

jr[/quote]

Na verdade a tua idéia com a loja era criar um site demo do projeto.

Já a minha é de disponibilizar uma página no site do vraptor com uma lista dos projetos como esse do Bronx para que o pessoal possa ler sobre e baixar o projeto. Mas não um live demo.

Abraços

posso ver de colocar isso no site sim! vou marcar como TODO aqui e fazer assim que possível =)

Muito interessante, porém para entender como usar na thread fica meio complicado.

Bronx porque não monta um tutorial explicando detalhadamente?

parabéns

abraços

Srs., vortei!

Só agora tive tempo para parar e mexer novamente nisso.
Fiz quase todas as alterações sugeridas pela galera. Só falta implementar o esquema de forçar 403 qnd necessário (útil para chamadas ajax).

Enfim, o que pega é que estou desde ontem tentando testar o que fiz, e não estou conseguindo pq quando empacoto tudo num jar, o VRaptor não encontra os componentes que estão dentro dele (lança uma “org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name […]”).

Alguém aí já passou por isso?

Já tentei marcando e desmarcando o “Add directory entries”, tentei colocar tudo dentro do próprio VRaptor, e nada…¬¬

O trace completo:

org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'accessControllerInterceptor' defined in file [C:\Users\Bronx\apache-tomcat-6.0.20\wtpwebapps\controle-acesso\WEB-INF\classes\br\com\bronx\interceptor\AccessControllerInterceptor.class]: Unsatisfied dependency expressed through constructor argument with index 1 of type [br.com.bronx.vraptor.restrictrex.restriction.RestrictionChecker]: : No matching bean of type [br.com.bronx.vraptor.restrictrex.restriction.RestrictionChecker] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {}; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching bean of type [br.com.bronx.vraptor.restrictrex.restriction.RestrictionChecker] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {}
	org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:698)
	org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:192)
	org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:984)
	org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:886)
	org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:479)
	org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:450)
	org.springframework.beans.factory.support.AbstractBeanFactory$2.getObject(AbstractBeanFactory.java:328)
	org.springframework.web.context.request.AbstractRequestAttributesScope.get(AbstractRequestAttributesScope.java:43)
	org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:324)
	org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:193)
	org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeansOfType(DefaultListableBeanFactory.java:385)
	org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeansOfType(DefaultListableBeanFactory.java:375)
	org.springframework.context.support.AbstractApplicationContext.getBeansOfType(AbstractApplicationContext.java:1069)
	org.springframework.beans.factory.BeanFactoryUtils.beansOfTypeIncludingAncestors(BeanFactoryUtils.java:221)
	br.com.caelum.vraptor.ioc.spring.VRaptorApplicationContext.getBean(VRaptorApplicationContext.java:240)
	br.com.caelum.vraptor.ioc.spring.SpringBasedContainer.instanceFor(SpringBasedContainer.java:58)
	br.com.caelum.vraptor.util.collections.Functions$1.apply(Functions.java:32)
	br.com.caelum.vraptor.util.collections.Functions$1.apply(Functions.java:1)
	com.google.common.collect.Lists$TransformingRandomAccessList.get(Lists.java:431)
	java.util.AbstractList$Itr.next(Unknown Source)
	com.google.common.collect.Iterators$7.computeNext(Iterators.java:602)
	com.google.common.collect.AbstractIterator.tryToComputeNext(AbstractIterator.java:135)
	com.google.common.collect.AbstractIterator.hasNext(AbstractIterator.java:130)
	com.google.common.collect.Lists.newArrayList(Lists.java:131)
	com.google.common.collect.Collections2$FilteredCollection.toArray(Collections2.java:219)
	br.com.caelum.vraptor.interceptor.DefaultInterceptorRegistry.interceptorsFor(DefaultInterceptorRegistry.java:50)
	br.com.caelum.vraptor.interceptor.InterceptorListPriorToExecutionExtractor.intercept(InterceptorListPriorToExecutionExtractor.java:42)
	br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:46)
	br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:59)
	br.com.caelum.vraptor.interceptor.FlashInterceptor.intercept(FlashInterceptor.java:80)
	br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:46)
	br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:59)
	br.com.caelum.vraptor.interceptor.ResourceLookupInterceptor.intercept(ResourceLookupInterceptor.java:67)
	br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:46)
	br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:59)
	br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:48)
	br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:59)
	br.com.caelum.vraptor.core.DefaultRequestExecution.execute(DefaultRequestExecution.java:62)
	br.com.caelum.vraptor.VRaptor$1.insideRequest(VRaptor.java:91)
	br.com.caelum.vraptor.ioc.spring.SpringProvider.provideForRequest(SpringProvider.java:55)
	br.com.caelum.vraptor.VRaptor.doFilter(VRaptor.java:88)

root cause

org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching bean of type [br.com.bronx.vraptor.restrictrex.restriction.RestrictionChecker] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {}
	org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoSuchBeanDefinitionException(DefaultListableBeanFactory.java:896)
	org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:765)
	org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:680)
	org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:771)
	org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:691)
	org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:192)
	org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:984)
	org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:886)
	org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:479)
	org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:450)
	org.springframework.beans.factory.support.AbstractBeanFactory$2.getObject(AbstractBeanFactory.java:328)
	org.springframework.web.context.request.AbstractRequestAttributesScope.get(AbstractRequestAttributesScope.java:43)
	org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:324)
	org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:193)
	org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeansOfType(DefaultListableBeanFactory.java:385)
	org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeansOfType(DefaultListableBeanFactory.java:375)
	org.springframework.context.support.AbstractApplicationContext.getBeansOfType(AbstractApplicationContext.java:1069)
	org.springframework.beans.factory.BeanFactoryUtils.beansOfTypeIncludingAncestors(BeanFactoryUtils.java:221)
	br.com.caelum.vraptor.ioc.spring.VRaptorApplicationContext.getBean(VRaptorApplicationContext.java:240)
	br.com.caelum.vraptor.ioc.spring.SpringBasedContainer.instanceFor(SpringBasedContainer.java:58)
	br.com.caelum.vraptor.util.collections.Functions$1.apply(Functions.java:32)
	br.com.caelum.vraptor.util.collections.Functions$1.apply(Functions.java:1)
	com.google.common.collect.Lists$TransformingRandomAccessList.get(Lists.java:431)
	java.util.AbstractList$Itr.next(Unknown Source)
	com.google.common.collect.Iterators$7.computeNext(Iterators.java:602)
	com.google.common.collect.AbstractIterator.tryToComputeNext(AbstractIterator.java:135)
	com.google.common.collect.AbstractIterator.hasNext(AbstractIterator.java:130)
	com.google.common.collect.Lists.newArrayList(Lists.java:131)
	com.google.common.collect.Collections2$FilteredCollection.toArray(Collections2.java:219)
	br.com.caelum.vraptor.interceptor.DefaultInterceptorRegistry.interceptorsFor(DefaultInterceptorRegistry.java:50)
	br.com.caelum.vraptor.interceptor.InterceptorListPriorToExecutionExtractor.intercept(InterceptorListPriorToExecutionExtractor.java:42)
	br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:46)
	br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:59)
	br.com.caelum.vraptor.interceptor.FlashInterceptor.intercept(FlashInterceptor.java:80)
	br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:46)
	br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:59)
	br.com.caelum.vraptor.interceptor.ResourceLookupInterceptor.intercept(ResourceLookupInterceptor.java:67)
	br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:46)
	br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:59)
	br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:48)
	br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:59)
	br.com.caelum.vraptor.core.DefaultRequestExecution.execute(DefaultRequestExecution.java:62)
	br.com.caelum.vraptor.VRaptor$1.insideRequest(VRaptor.java:91)
	br.com.caelum.vraptor.ioc.spring.SpringProvider.provideForRequest(SpringProvider.java:55)
	br.com.caelum.vraptor.VRaptor.doFilter(VRaptor.java:88)

Enfim, se puderem ajudar, agradeço.

Já pensei umas 4 vezes em tacar o note na parede de tão puto que fiquei…kkkk

Mas é isso…

Ahhh… Para os que estavam comentando sobre as falhas do meu Roles: dá pra fazer diferente (do jeito que vocês querem - e é melhor), usando as coisas do jeito que estão! Basta abstrair as Roles que vc utiliza na annotation, e criar perfis mais “dinâmicos” que possuam tais roles.

Assim que tiver a implementação toda fechada farei um tutorial sobre tudo isso.

Fechando: por favor, me ajudem! hehehe

Abs a todos!

vc lembrou de colocar

<context-param> <param-name>br.com.caelum.vraptor.packages</param-name> <param-value>br.com.bronx.vraptor.restrictrex</param-value> </context-param>

no seu web.xml ???

pra arquivos dentro de jars isso é necessário

Então Lavieri,

Eu fiz isso sim, porém só utilizei o prefixo br.com.bronx.

Vou tentar com o caminho mais específico.

Mas como disse, não consegui injetar nem classes que criei dentro do próprio VRaptor…=/

De qualquer forma, vou testar aqui e já digo se rolou ou não.

Lavieri, era isso mesmo.

Acho que das outras vezes que usei o param “packages”, eu não tinha adicionado as entradas dos diretórios ao JAR!

Mas enfim, tá aí! Em mãos!

Novamente, o “changelog”:

  • Agora basta usar as annotations @LoginPage e @AccessDeniedPage para informar os caminhos de redirecionamento, em caso de acesso negado.
    Os métodos antigos continuam válidos (RestrictionChecker.setDefaultLogin/AccessDeniedPage e a annotation @OnAccessDenial), para situações mais específicas;
  • Em caso de acesso negado por motivo de o usuário não possuir as credenciais necessárias (Roles ou Access Level suficientes), e nenhuma AccessDeniedPage for informada, nenhuma exception é lançada e o retorno é o HTTP 403 que a galera pediu (ótima sugestão);
  • Para forçar o “forbidden” (HTTP 403), faça o seguinte:
@OnAccessDenial(forceHttp403 = true)
public void meuMetodo(...){}

Com isso, mesmo tendo sido especificado um caminho para redirecionamento em caso de acesso negado, o servidor manda um 403 para o cliente.

Vale ressaltar que só pode haver um método anotado com @LoginPage ou @AccessDeniedPage (pode ser o mesmo método), e que o método não deve receber nenhum parâmetro.

Bom, acho que essa versão contempla 97% das sugestões que foram surgindo.
No mais, não fiz o @LogoutPage pois acho que isso deve ficar a cargo da lógica do cara (método de logout da aplicação), bastanto um simples redirecionamento via result.

Deixei o interceptor fora do pacote para que possam alterar da maneira que desejarem.
Na minha aplicação teste, criei um componente de sessão que guarda informações do usuário (UsuarioCorrente). Não precisam deixar assim, a única obrigatoriedade é passar um método e um Profile para o método checkRestrictions da classe RestrictionsChecker.

Por favor, peço novamente que testem. Confesso que foi a versão que menos testei, então ainda pode estar longe de ser “defect free”…rs

Assim que possível farei um manual detalhado, pois muita gente tem caído de paraquedas aqui, e seria uma boa para “consolidar” a documentação de tudo que foi feito.

Seguem os arquivos.

TESTEM! rs

Abs.

[quote=bronx]Vale ressaltar que só pode haver um método anotado com @LoginPage ou @AccessDeniedPage (pode ser o mesmo método), e que o método não deve receber nenhum parâmetro.
[/quote]

Bronx, acho que vc poderia retirar essa restrição, de os métodos não terem parametros, da pra redirecionar com parametros sem problemas, eu tenho um projeto muito parecido com o seu, que também disponibilizei o código, vou linkar aqui o SRC de como redireciono paras lógicas, e mesmo elas tendo parametros…

isso é especialmente útil para uma página de login

[code]
@LoginPage
public void login(String login, String senha) {

}[/code]

claro que esse lógica deve esperar login e senha nulos, no caso de quando é o seu sistema que fizer redirect…

com este objeto abaixo vc consegue criar rotas mesmo com parametros, e para redirecionar, para usar é simples.

http://code.google.com/p/access4vraptor/source/browse/trunk/src/main/java/br/com/simtecnologia/acesso/controle/DefaultLogicRoute.java

new DefaultLogicRoute(resourceMethod).redirectTo(result);

este classe aceita também no construtor MethodInfo, e diretamente a classe e metodo da lógica

Lavieri,

Eu tinha visto o que vc fez! Parabés pelo trabalho.
Aliás, pelos trabalhos. Vi que não foi a única contribuição que fez. Achei legal que algumas que você fez eu tbm fiz aqui. Acho que estamos trabalhando num sistema semelhante, pois estamos tendo os mesmos problemas. Hehehe

Quanto a página de login:

É que estamos tendo abordagens diferentes quanto aos métodos do controller.

Você utiliza o mesmo método para carregar a página de login e para de fato efetuar o login.

Eu separo essas funções em métodos distintos. Acho que isso deixa as coisas mais organizadas, além daquela questão de dividir as responsabilidades dos métodos. Saca só:


@LoginPage
public void login() {

}

É um método que não faz nada, pois foi criado única e exclusivamente para mostrar a página de login.

Para não dizer que não faz nada, dá pra colocar uma lógica para não deixar um usuário já logado ir novamente para a página de login:

@LoginPage
public void login() {
    if (isAlreadyLoggedIn())
        this.result.redirectTo(MeuController.class).metodoQualquer();
}

Na minha login.jsp, eu faria algo do tipo:

(...)
<form name="loginForm" method="post" action="<c:url value='/efetuar/login'/>">

    Usuário:
    <input type="text" name="usuario.nome" /><br/>
    Usuário:
    <input type="password" name="usuario.senha" /><br/>
    <input type="submit" />

</form>
(...)

Como pode ver, a action do form aponta para outro método, que é o que vai realizar de fato o login:

@Path("/efetuar/login")
public void efetuarLogin(Usuario usuario) {
    //lógica de login
}

Enfim…

Eu estava considerando deixar utilizar parâmetros, mas acabei não enxergando a real necessidade disso…

Mas por favor, teste aí e me diga o que acha.

E obrigado pela sugestão! :thumbup:

Entendo o que quer dizer, e quanto a separação de responsabilidades ^^ …

eu não custumo a colocar @Get e @Post na mesma lógica, porem minha intenção é de não restringir e dar a possibilidade de usar… o metodo de login no meu projeto e o que mostrei aqui, são apenas exemplos simplorios de como pode ser efetuado um login… eu faço alguma presuposições, inclusive a de que quem acessar a pagina de login, quer se logar, e se alguem logado a acessa, então é melhor que abra a pagina de login, e que deiche ele tentar logar.

outra coisa é que login é uma lógica vazia, que só exibe o form, e efetualogin é uma lógica que tenta logar, e se não consegue também exibe o form, então da pra ter uma lógica login, que posta pra ela mesma sem muitos problemas.

além de quer, presuposições são sempre ruim, quando se faz algo generico, como não é possivel checar em tempo de compilação o que o cara anota com @LoginPage, é melhor não lançar uma exceção na cara dele em tempo de execução…

Parabéns pelo projeto Bronx.
Estou tentando utilizá-lo no meu projeto, poderiam me ajudar?

Tenho as seguintes classes

//modifiquei o nome da classe Usuario que tu passou, para UsuarioProfile, para fins de estudo
public class UsuarioProfile implements Profile{
	
	private int accessLevel;
	private List<String> roles;
	
	public int getAccessLevel() {
		/*Poderia buscar o nível de acesso no 
		 * banco de dados, por exemplo.
		 */
		this.accessLevel = 1;//para fins de teste, no futuro pegarei do banco
		return this.accessLevel;
	}
	
	public List<String> getRoles() {
		/*Poderia buscar os papéis deste usuário  
		 * no banco de dados, por exemplo.
		 */
		this.roles.add("jogador");//para fins de teste, no futuro pegarei do banco
		return this.roles;
	}

	public boolean isLoggedIn() {
		// TODO Auto-generated method stub
		return false;
	}

Meu Usuario(Bean), criado pelo Hibernate, está assim

@Entity
@Table(name = "usuario", catalog = "bolao")
public class Usuario implements java.io.Serializable {

	private Profile profile;
	private int id;
	private String nome;
	private String login;
	private String senha;
	private String email;
	private String telefone;
	private String ip;
	private Set<Jogador> jogadors = new HashSet<Jogador>(0);

//....

//isso aqui está certo? É assim que devo fazer?
public void setPerfil(Profile profile){
		this.profile = profile;
	}
	
	public Profile getPerfil(){
		return this.profile;
	}

Adaptei seu interceptor, da seguinte forma

//esse Usuario que estou passando aqui, é meu Usuario(Bean), que referencia o BD de acordo com as regras do Hibernate
public AccessControllerInterceptor(Usuario usuarioCorrente, RestrictionChecker restrictionChecker,
							Result result){
                //aqui, seu usuario corrente é um Bean, correto? Logo tenho que passar meu Bean certo?

		this.result = result;
		this.restrictionChecker = restrictionChecker;
		this.usuarioCorrente = usuarioCorrente;
	}

DEntro do Interceptor acima, devo fazer assim?

   restrictionResult = this.restrictionChecker.checkRestrictions(resourceMethod.getMethod(), this.usuarioCorrente.getPerfil());

A Interface Login está assim

public interface Login {
	public boolean isLoggedIn();
	public void setLoggedIn(boolean loggedIn);
	public Profile getProfile();
	public void setProfile(Profile profile);
}

E meu LoginController está assim

import br.com.bolao.accessControl.LoginControl;
import br.com.bolao.bean.Usuario;
import br.com.bolao.dao.UsuarioDao;
import br.com.bronx.vraptor.restrictrex.annotation.AccessDeniedPage;
import br.com.bronx.vraptor.restrictrex.annotation.LoginPage;
import br.com.caelum.vraptor.Resource;
import br.com.caelum.vraptor.Result;

@Resource
public class LoginController {
	
	private LoginControl loginControl;
	private Result result;
	private UsuarioDao daoUsuario;

	public LoginController(LoginControl loginControl, Result result,
			UsuarioDao daoUsuario) {
		this.loginControl = loginControl;
		this.result = result;
		this.daoUsuario = daoUsuario;
	}

	@LoginPage
    public void login() {}

    @AccessDeniedPage
    public void accessDenied() {}
    
    public void logar(String login, String senha){
        //busco no banco login e senha, caso encontre, é montado o objeto Usuario, que possui atributos ID, NOME, TELEFONE, EMAIL eeee PERFIL, estou fazendo certo?
    	Usuario user = daoUsuario.login(login, senha);
    	if (user != null){
    		loginControl.setLoggedIn(true);
    		loginControl.setProfile(user.getPerfil());
    	}
    }
}

Galera, como podem ver, ainda sou newbie em VRaptor, e estou tentando adaptar sua contribuição ao meu projeto. Ainda não está claro algumas coisas para mim, como por exemplo o método que está dentro do Usuario(aquele que implementa Profile)

public boolean isLoggedIn() {
		// TODO Auto-generated method stub
		return false;//quando vou retornar true, e como fazer isso?
	}

Garanto que minhas perguntas podem parecer bobas, mas preciso de um auxílio de como andar com esse projeto.
Como fazer o checkRestriction? Onde? Quando?

Obrigado desde já aos que me ajudarem, boa noite, e Feliz Páscoa

Não vou conseguir te ajudar muito nesse projeto aki, mas vamos la…

a classe UsuarioProfile, vc deve implementar ela mais ou meno assim:

//modifiquei o nome da classe Usuario que tu passou, para UsuarioProfile, para fins de estudo
public class UsuarioProfile implements Profile{
	
	private int accessLevel;
	private List<String> roles;

	private Usuario usuario;

	public void login(Usuario usuario) {
		this.usuario = usuario;
	}
	
	public int getAccessLevel() {
		this.accessLevel = 1;//para fins de teste, no futuro pegarei do banco

		//o ideal é fazer this.accessLevel = (usuario == null) ? -1 :  usuario.getAccessLevel();
		//ou seja... se usuario não existir seta o nivel = -1

		return this.accessLevel;
	}
	
	public List<String> getRoles() {
		this.roles.add("jogador");//para fins de teste, no futuro pegarei do banco

		//o ideal é fazer return (usuario == null) ? Collections.emptyList() : usuario.getRoles();
		//se não tem usuario, retorna uma lista vazia, caso contrario retorna a lista de roles do usuario.

		return this.roles;
	}

	public boolean isLoggedIn() {
		return usuario != null;
	}

 	public void logout() {usuario = null;}

isso resolve algum de seus problemas, espero ter ajudado

Olá pessoal!
Estou testando o controlador de login do Diego, mas surgiu um probleminha aqui nesta linha:

restrictionResult = this.restrictionChecker.checkRestrictions(resourceMethod.getMethod(), this.usuarioLogado.getUsuario());

É nessa linha que ele verifica se o usuário está logado ou não?

Estas são as opções que ele me dá:

Estou usando a classe UsuarioLogado e LoginController que estão na apostila da Caelum.

<Editado: Agora que reparei que lá na primeira página do tópico o Diego postou as classes para usar com a interface Profile que já está no pacote =/ >

Vou ter q adaptar as classes pra usar daquela forma.

Abraço!

obs: poderiam criar uma seção desses plugins pro VRaptor no site do VRaptor, pq tô que nem barata tonta caçando as dicas pelas páginas. =)

[quote=Guevara]
obs: poderiam criar uma seção desses plugins pro VRaptor no site do VRaptor, pq tô que nem barata tonta caçando as dicas pelas páginas. =)[/quote]
já tem uma issue lá no github pra fazer isso:

provavelmente da próxima vez que a gente atualizar esse site vai ter uma seção disso =)

Legal Lucas!! Isso vai ser muito bom! =)
Seria ótimo se tivesse tutoriais no estilo das apostilas da Caelum, mostrando os códigos e dando exemplos de implementação.

Ainda estou ralando aqui nas classes, tô tentando adaptar o que eu tinha mas não estou conseguindo.

Eu tinha usuarioLogado e LoginController funcionando normalmente, agora pra usar esse método de controle tive q deletar os dois e criar uma Interface Login, o Interceptor AccessControllerInterceptor e a classe LoginControl implementando a classe Login, até ai beleza.
De quem o restrictionChecker obtém se o usuário está logado ou não? É do LoginControl? E como o LoginControl obtém o role do usuário?

Minha classe usuário está assim:

@Entity
public class Usuario {
	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	@Column(name="id_usuario")
	private Long idUsuario;	
	private String login;
	private String senha;
	private String nome;
	private String role;
        //getters e setters

Criei o atributo role pra gravar no banco se é admin, vendedor ou qualquer outra coisa.

Agora não sei onde implemento de fato o login, logout, busca pelo login e senha como era nas classes usuarioLogado e LoginController. Me perdi. =/

Abraço!

Fala brother. Jóia?

Cara, a última versão do controle de acesso que fiz só possui a interface Profile. Tá bem mais fácil implementar as coisas. Acho que na 5ª página do tópico eu expliquei como utilizar a nova versão.

Estou meio sem tempo para escrever um tutorial da nova versão, mas vamos lá:

O método checkRestrictions recebe um método e um Profile. Ele verifica se o Profile passado como parâmetro possui permissão para acessar aquele método.

Como funciona: o cara faz o login normalmente (vc nao precisava ter mudado isso no seu código). De alguma forma (via cookie ou sessão do browser), vc sabe qual é o usuário logado. A ideia é gerar um Profile baseado nesse usuário.

Aí vc segue seu coração.

Você pode fazer de N maneiras. Uma possibilidade seria:

Primeiro, vc cria um componente que fica na sessão. Esse componente armazenará o usuário logado enquanto a sessão estiver ativa, ou até que o usuário saia do sistema (logout):

/*
 * Componente que fica na sessão do servidor, 
 * armazenando o usuário logado.
 */

@Component
@SessionScoped
public class UsuarioCorrente {
	
	private Usuario usuarioCorrente;

	public void setUsuarioCorrente(Usuario usuarioCorrente) {
		this.usuarioCorrente = usuarioCorrente;
	}

	public Usuario getUsuarioCorrente() {
		return this.usuarioCorrente;
	}
	
	public Perfil getPerfil() {
		Perfil perfil = new Perfil();
		if (this.usuarioCorrente != null) {
			perfil.setLoggedIn(true);//como o usuário corrente não é nulo, significa que ele está logado
			//o nível de acesso vc obtém de onde quiser (banco de dados, arquivo properties etc)
			//caso não utilize níveis de acesso no seu controle de acessos, não precisa informar o accessLevel
			//perfil.setAccessLevel(0);
			//Especificamente no seu caso, cada usuário possui apenas um role. Então, faça simplesmente isso:
			List<String> roles = new ArrayList<String>();
			roles.add(this.usuarioCorrente.getRole());
			perfil.setRoles(roles);
		}
		return perfil;
	}

}

Na hora de logar (no método de login do seu LoginController) vc pode fazer o seguinte:

@Resource
public class LoginController {
	
	private Result result;
	private UsuarioCorrente usuarioCorrente;
	private Validator validator;

	public LoginController(Result result, UsuarioCorrente usuarioCorrente,
						Validator validator) {
		this.result = result;
		this.usuarioCorrente = usuarioCorrente;
		this.validator = validator;
	}
	
	@LoginPage//essa anotação indica que essa é a página de login
	public void login() {
		if (this.usuarioCorrente.getPerfil().isLoggedIn())//caso o usuário já esteja logado, redirecione-o para a página principal
			this.result.redirectTo(MeuController.class).principal();
	}

	public void logar(Usuario usuario) {
		/*
		 * Busca o usuario no banco de dados.
		 */
		if (/*usuário não encontrado - senha ou nome de usuário inválidos errada  */) {
			/*volta para a página de login com a mensagem de erro.*/
			this.validator.add(new ValidationMessage("Usuário/Senha inválidos", "login.fail"));
			this.validator.onErrorUse(Results.logic()).redirectTo(LoginController.class).login();
		} else /*usuário encontrado*/{
			this.usuarioCorrente.setUsuarioCorrente(usuario);//guardo o usuário na sessão
			this.result.redirectTo(MeuController.class).principal();//redireciono para a página principal
		}
	}

	public void logout() {
		/*na hora de sair, ele "apaga" o usuário logado (atribui "null" a ele)*/
		this.usuarioCorrente.setUsuarioCorrente(null);
		this.result.redirectTo(LoginController.class).login();//redireciona para a página de login
	}

}

Na classe UsuarioCorrente, eu criei um método getPerfil(). Perfil é uma classe que implementa a interface Profile. Saca só:


public class Perfil implements Profile {

	private int accessLevel;
	private List<String> roles = new ArrayList<String>();
	private boolean loggedIn;
	
	@Override
	public int getAccessLevel() {
		return this.accessLevel;
	}
	
	public void setAccessLevel(int accessLevel) {
		this.accessLevel = accessLevel;
	}

	@Override
	public List<String> getRoles() {
		return this.roles;
	}

	public void setRoles(List<String> roles) {
		this.roles = roles;
	}

	@Override
	public boolean isLoggedIn() {
		return this.loggedIn;
	}

	public void setLoggedIn(boolean loggedIn) {
		this.loggedIn = loggedIn;
	}


}

Os métodos anotados com @Override são as implementações da interface Profile. Os demais eu criei para facilitar.

No interceptor, faça:

/**
 * This interceptor controls the access to the resources, based on their
 * restrictions annotations.<br>
 * The restrictions might be method restrictions or resource restrictions,
 * according to where the annotations had been placed.
 * 
 * @author Diego Maia da Silva a.k.a. Bronx
 */
@Intercepts
public class AccessControllerInterceptor implements Interceptor {

	private RestrictionChecker restrictionChecker;
	private Result result;
	private UsuarioCorrente usuarioCorrente;
	
	public AccessControllerInterceptor(UsuarioCorrente usuarioCorrente, RestrictionChecker restrictionChecker,
							Result result){
		this.result = result;
		this.restrictionChecker = restrictionChecker;
		this.usuarioCorrente = usuarioCorrente;
	}
	
	@Override
	public boolean accepts(ResourceMethod method) {
		return this.restrictionChecker.hasRestriction(method.getMethod());
	}

	
	public void intercept(InterceptorStack stack, ResourceMethod resourceMethod,
			Object resourceInstance) throws InterceptionException {
		RestrictionResult restrictionResult;
		/*
		this.restrictionChecker.setDefaultAccessDeniedPage("/access/denied/page");
		Não precisa mais utilizar esses métodos, mas se quiser, vc pode continuar utilizando-os. 
		Ao invés disso, utilize as annotations @LoginPage e @AccessDeniedPage.
		this.restrictionChecker.setDefaultLoginPage("/login/page");
		*/
		try {
			restrictionResult = this.restrictionChecker.checkRestrictions(resourceMethod.getMethod(), this.usuarioCorrente.getPerfil());
		} catch (RestrictionAnnotationException exception) {
			throw new InterceptionException(exception);
		} catch (DestinationException exception) {
			throw new InterceptionException(exception);
		}
		if (restrictionResult.isRestricted()){
			if (restrictionResult.isHttp403()) {
				this.result.use(Results.http()).sendError(403);
			} else {
				this.result.use(Results.page()).redirect(restrictionResult.getDestination());
			}
		} else {
			stack.next(resourceMethod, resourceInstance);
		}
	}
}

Detalhe para essa linha:

			restrictionResult = this.restrictionChecker.checkRestrictions(resourceMethod.getMethod(), this.usuarioCorrente.getPerfil());

Nela o método checkRestrictions recebe o método e o Profile que usará na validação. No caso, o profile que ele recebe é uma instância da classe Perfil, gerada com os dados do usuário logado.

Teste ae…escrevi bem rápido, mas acho que dá pra entender.
Se possível, leia os posts da página 5.

Mas cara, não se esqueça que vc pode implementar sua solução da maneira que quiser. Essa que eu postei é uma bem trivial, então fica a cargo do desenvolvedor julgar a melhor maneira de implementar a parada.

Enfim, qualquer coisa, continue gritando.

Abs.

Fala Bronx!
Obrigado pela ajuda! Acho que está td certo, parece que ficou faltando apenas liberar o IndexController lá no Accepts, dá uma olhada:

org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching bean of type [br.com.bronx.vraptor.restrictrex.restriction.RestrictionChecker] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {}
	org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoSuchBeanDefinitionException(DefaultListableBeanFactory.java:896)
	org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:765)
	org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:680)
	org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:771)
	org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:691)
	org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:192)
	org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:984)
	org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:886)
	org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:479)
	org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:450)
	org.springframework.beans.factory.support.AbstractBeanFactory$2.getObject(AbstractBeanFactory.java:328)
	org.springframework.web.context.request.AbstractRequestAttributesScope.get(AbstractRequestAttributesScope.java:43)
	org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:324)
	org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:193)
	org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeansOfType(DefaultListableBeanFactory.java:385)
	org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeansOfType(DefaultListableBeanFactory.java:375)
	org.springframework.context.support.AbstractApplicationContext.getBeansOfType(AbstractApplicationContext.java:1069)
	org.springframework.beans.factory.BeanFactoryUtils.beansOfTypeIncludingAncestors(BeanFactoryUtils.java:221)
	br.com.caelum.vraptor.ioc.spring.VRaptorApplicationContext.getBean(VRaptorApplicationContext.java:240)
	br.com.caelum.vraptor.ioc.spring.SpringBasedContainer.instanceFor(SpringBasedContainer.java:58)
	br.com.caelum.vraptor.util.collections.Functions$1.apply(Functions.java:32)
	br.com.caelum.vraptor.util.collections.Functions$1.apply(Functions.java:30)
	com.google.common.collect.Lists$TransformingRandomAccessList.get(Lists.java:431)
	java.util.AbstractList$Itr.next(AbstractList.java:345)
	com.google.common.collect.Iterators$7.computeNext(Iterators.java:602)
	com.google.common.collect.AbstractIterator.tryToComputeNext(AbstractIterator.java:135)
	com.google.common.collect.AbstractIterator.hasNext(AbstractIterator.java:130)
	com.google.common.collect.Lists.newArrayList(Lists.java:131)
	com.google.common.collect.Collections2$FilteredCollection.toArray(Collections2.java:219)
	br.com.caelum.vraptor.interceptor.DefaultInterceptorRegistry.interceptorsFor(DefaultInterceptorRegistry.java:50)
	br.com.caelum.vraptor.interceptor.InterceptorListPriorToExecutionExtractor.intercept(InterceptorListPriorToExecutionExtractor.java:42)
	br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:46)
	br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:59)
	br.com.caelum.vraptor.interceptor.FlashInterceptor.intercept(FlashInterceptor.java:80)
	br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:46)
	br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:59)
	br.com.caelum.vraptor.interceptor.ResourceLookupInterceptor.intercept(ResourceLookupInterceptor.java:67)
	br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:46)
	br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:59)
	br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:48)
	br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:59)
	br.com.caelum.vraptor.core.DefaultRequestExecution.execute(DefaultRequestExecution.java:62)
	br.com.caelum.vraptor.VRaptor$1.insideRequest(VRaptor.java:91)
	br.com.caelum.vraptor.ioc.spring.SpringProvider.provideForRequest(SpringProvider.java:55)
	br.com.caelum.vraptor.VRaptor.doFilter(VRaptor.java:88)

Na apostila da Caelum o Accepts ficaria assim:

public boolean accepts(ResourceMethod method) {
	    ResourceClass resource = method.getResource();
	    return !IndexController.class.isAssignableFrom(resource.getType());	
	}	

No seu Accepts está assim:

public boolean accepts(ResourceMethod method) {
		return this.restrictionChecker.hasRestriction(method.getMethod());
	}

A saida de erro seria referente a isso ou é outra coisa?
Outra coisa, a classe Perfil, fica sem anotação?

Abraço!