Minha contribuição - Controle de acesso VRaptor 3

Gostei do “VAAS”, rs
Eu tinha feito um mais amador para um sistema, vou testar a sua solução e depois retorno como foi. E vou aproveitar e testa-la numa situação bem especifica em termos de segurança q estou modelando.

Parabéns pela iniciativa
:wink:

Não precisa estar integrada ao VRaptor pra isso funcionar…

basta implementar uma interface interna do VRaptor…
( criar a classe:
@ApplicationScoped @Component public class PageHandler implements StereotypeHandler {…})
depois eu te explico melhor como fazer…

dá uma olhada nesses artigos:

http://vidageek.net/2009/06/08/como-migrar-de-svn-para-git/
http://vidageek.net/2009/07/06/git-workflow/

Nova versão galera!

Me desculpem o atraso de 2 dias, mas aqui está a versão alterada com algumas melhorias propostas pela galera.

O “change log”:

  • classe RestrictionChecker anotada com @Component; //eu não consegui injetá-la :frowning: .
  • criação dos métodos setDefaultLoginPage e setDefaultAccessDeniedPage na classe RestrictionChecker;
  • alteração do nome da annotation @AccessDenied para @OnAccessDenial;
  • restrição do target das annotations: agora é só TYPE e METHOD.
  • criação de exception específica em caso de o desenvolvedor não informar login page ou access denied page em nenhum lugar;
  • atributo “roles” da annotation @Roles agora é uma lista, eliminando a necessidade do antigo “separator” (thanks Leonardo3001);
  • necessidade de implementar apenas uma interface: Profile;
  • adoção temporária do nome “RestricTRex”…ainda estou aguardando as sugestões (rs).

A maneira de utilização é basicamente a mesma.

Com os métodos setDefaultLoginPage e setDefaultAccessDeniedPage não existe mais a obrigação de uso da anotação @OnAccessDenial (antiga @AccessDenied). Mas sua utilização ainda é possível, caso seja necessário um comportamento mais específico em determinadas situações.
Os métodos setDefaultLoginPage e setDefaultAccessDeniedPage devem ser chamados ANTES da chamada ao método checkRestrictions.

A interface Profile agora possui a seguinte “cara”:

public interface Profile {

	public boolean isLoggedIn();
	public List<String> getRoles();
	public int getAccessLevel();
	
}

Olha só o interceptor como pode ficar (façam como quiserem):

package br.com.bronx.interceptor;

import br.com.bronx.restrictrex.exception.DestinationException;
import br.com.bronx.restrictrex.exception.RestrictionAnnotationException;
import br.com.bronx.restrictrex.interfaces.Profile;
import br.com.bronx.restrictrex.restriction.RestrictionChecker;
import br.com.bronx.restrictrex.restriction.RestrictionResult;
import br.com.caelum.vraptor.InterceptionException;
import br.com.caelum.vraptor.Intercepts;
import br.com.caelum.vraptor.Result;
import br.com.caelum.vraptor.core.InterceptorStack;
import br.com.caelum.vraptor.interceptor.Interceptor;
import br.com.caelum.vraptor.resource.ResourceMethod;
import br.com.caelum.vraptor.view.Results;

/**
 * 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 Profile profile;
	
	public AccessControllerInterceptor(Profile profile, Result result, RestrictionChecker restrictionChecker){
		this.restrictionChecker = restrictionChecker;
		this.profile = profile;
		this.result = result;
	}
	
	@Override
	public boolean accepts(ResourceMethod method) {
		return this.restrictionChecker.hasRestriction(method.getMethod());
	}

	public void intercept(InterceptorStack stack, ResourceMethod resourceMethod,
			Object resourceInstance) throws InterceptionException {
		//this.restrictionChecker.setDefaultLoginPage("minha/pagina/de/login/padrao");
		//this.restrictionChecker.setDefaultAccessDeniedPage("pagina/de/acesso/restrito/padrao");
		RestrictionResult restrictionResult;
		try {
			restrictionResult = this.restrictionChecker.checkRestrictions(resourceMethod.getMethod(), this.profile);
		} catch (RestrictionAnnotationException e) {
			throw new InterceptionException(e);
		} catch (DestinationException e) {
			throw new InterceptionException(e);
		}
		if (restrictionResult.isRestricted()){
			result.use(Results.page()).redirect(restrictionResult.getDestination());
		} else {
			stack.next(resourceMethod, resourceInstance);
		}
	}
}

Enfim…testem aí.

Planos para um futuro [extremamente] próximo: jogar isso tudo no github e implementar o esquema da @LoginPage e @AccessDeniedPage.

Lucas, me mande um tutorial de como fazer esse esquema do StereotypeHandler.

[]'s

EDIÇÃO: esqueci do anexo…damn it…!

só criar a classe dentro do seu projeto:

@Component
@ApplicationScoped
public class LoginPageHandler implements StereotypeHandler {

    public LoginPageHandler(RestrictionChecker checker) {
    //guarda num field
    //O RestrictionChecker tem que ser ApplicationScoped (se ele depender de algo do request 
    //não vai rolar, então vc vai ter que criar uma outra classe que tem essas configurações de loginPage)
}
    public Class<? extends Annotation> stereotype() {
         return Resource.class; // só vai funcionar pros Controllers
    }

    public void handle(Class<?> type) {
          if (//algum dos métodos de type está anotado com @LoginPage) {
              this.checker.setDefaultLoginPage(//o metodo anotado);
          }
          // mesma coisa para @AccessDeniedPage
    }
}

essa classe é carregada qdo o VRaptor está se configurando… toda vez que ele achar alguma classe anotada com @Resource, ele vai chamar o método handle(…) passando essa classe

Muito boa a contribuição Bronx, parabéns…

apenas uma sugestão, que tal dar mais flexibilidade para as roles, substituindo:

@Roles(roles={"gerente","supervisor"},  policy = RolesPolicy.DISJUNCTION) 

por:

@Roles(roles="gerente OU supervisor E ....") 

Lucas:

[youtube]http://www.youtube.com/watch?v=dsbrRXMdLMc[/youtube]

Muito simples man!
VRaptor surpreendendo cada dia que passa…rs
E como eu faria para redirecionar? Eu teria a classe e o método. Como faria para redirecionar para o método especificado??

wpivotto:

[youtube]http://www.youtube.com/watch?v=DeVmYfiGydo[/youtube]

Hehe! Brincadeiras a parte: cara, isso pode gerar problemas. Além de um trabalho maior para codificar um “parser” para a string, pois a mesma precisaria de agrupamentos (uso de parênteses) e o cacete a 4.
O cara poderia digitar errado, dentre outros possíveis erros…

De qualquer forma, valeu pela sugestão. E por favor, teste! rs

ok bronx, faz sentido…

eu consegui redirecionar para o método da seguinte maneira


@Component  
@ApplicationScoped  
public class LoginPageHandler implements StereotypeHandler {  

	private final RestrictionChecker checker;
	private final Router router;
	private static final Logger logger = LoggerFactory.getLogger(LoginPageHandler.class);

	public LoginPageHandler(RestrictionChecker checker, Router router) {  
		this.checker = checker; 
		this.router = router;
	}  

	public Class<? extends Annotation> stereotype() {  
		return Resource.class; 
	}  

	public void handle(Class<?> type) {  

		for(Method method : type.getMethods()){

			String route = router.urlFor(type, method, method.getGenericParameterTypes());

			if(method.isAnnotationPresent(LoginPage.class)) {
				checker.setDefaultLoginPage(route);
				logger.info("DEFAULT LOGIN PAGE -> " + route);
			}

			if(method.isAnnotationPresent(AccessDeniedPage.class)) {
				checker.setDefaultAccessDeniedPage(route);
				logger.info("DEFAULT ACCESS DENIED PAGE -> " + route);
			}
		}
	} 
	
}  

O Lucas deve ter uma solução melhor…

Seria legal ter uma anotação LogoutPage também…

se vc quiser redirecionar para o método e classe vc faz assim:

Object instance = result.redirectTo(classe);
new Mirror().on(instance).invoke().method(metodo).withoutArgs(); //supondo que não tem argumentos

se vc quiser só a url faz como o wpivotto falou… o único erro dele é o último parâmetro do urlFor… se eu não me engano ele recebe um Object[] que são os argumentos… o ideal seria forçar que o método anotado não receba argumentos, assim é só passar new Object[0] como último argumento

Lucas e wpivotto,

Estamos a um passo de fecharmos isso. rs

Mas Lucas, e no caso do método possuir parâmetros?
Você acha melhor forçar que os métodos com @LoginPage e @AccessDeniedPage não possuam parâmetros?

Posso estar enganado, mas acredito que isso acaba tirando um pouco da flexibilidade proposta pela ferramenta, não acha?

Anyway, vou fazer isso tudo até o fds e mando nova versão da parada. Master ocupado para parar e fazer isso agora…=S
Abs.

se o método possui parâmetros, o que vc vai passar pra ele? Vc não tem essa informação… passar tudo null não é uma boa, pq o método provavelmente usa as informações

Nossa…eu misturei tudo… Tava pensando na injeção dos parâmetros do construtor da classe quando escrevi isso. =S
#groselhadetected
My bad. :oops:

Então fechou!

Logo mais teremos a versão mais elegante do restritor! =DDD

[quote=bronx]Opa!
Então garcia-jj, esse esquema é específico para o VRaptor. Vale lembrar que nem todos usuários do VRaptor conhecem ou sabem utilizar o JAAS (eu mesmo nem imagino como funciona…=S). Qualquer Servlet Container possui suporte a JAAS?
Agora fiquei curioso: vc utiliza JAAS com o VRaptor? É simples? Vou dar uma estudada ASAP.

Quanto ao CoC: concordo.
Tanto que estamos justamente elaborando uma solução mais simples para não termos que fazer essas configurações em todas as classes/métodos do sistema. A idéia do loginPage é dar o máximo de flexibilidade ao desenvolvedor. Pode existir uma situação onde, antes de ir para a página de login, ele queira exibir alguma informação ao usuário, por exemplo (??? sei lá rs). Mas de qualquer modo, é essa linha que pretendemos adotar: a menor quantidade de configurações possíveis.

Valeu pela contribuição. Será de grande valia!!
[/quote]

bronx, tudo bem? Desculpe a demora em responder. Eu estava em viagem de trabalho. Mas vamos lá ao que interessa.

Qualquer servlet container suporta JAAS. A grande vantagem dele é ser um padrão, porém não é nada simples. A tua solução de longe é a mais simples. Eu sempre sugiro usar JAAS porque todos os projetos que faço usam EJB, assim ambos conversam transparente entre sí.

E achei a tua contribuição fantástica. O que você acha de disponibilizar o projeto como uma espécie de plugin para o vraptor? Assim é só colocar um jar do tipo vraptor-plugin-do-bronx.jar e ser feliz, hehe.

Abraços

Boa tarde garcia-jj!

Hehe…me expressei mal. Queria saber se possuem suporte “nativo”. Sem precisar de JARs extras. rs

Enfim…cara, já está assim! Já está tudo dentro do jar. É baixar, configurar e usar! o//

Mas estamos melhorando. Acho que semana que vem já teremos versão nova por aí. rs

Abs.

Sim, a implementação de JAAS fica no container.

Amigo boneazul!
Eu gostei muito do teu modelo para controlar o acesso e segurança, porém acredito que ficaria muito melhor se você utilizar o nome do método anotado ao invés de uma Ação numerada, pois assim o desenvolvedor não precisaria se preocupa em saber qual ação deverá ser associada ao método/lógica, mas ficaria bastante elegante se na anotação @VerifyAccess pudesse informar 3 parâmetros, onde:

@VerifyAccess(description=“Relatório gerencial|Esta lógica serve para imprimir o relatório gerencial.”,
pageAccessDenied="/acessoNegado.jsp",
messageAccessDenied=“acesso.negado”
)

Sendo assim:
description= Aqui seria informado uma chave do arquivo i18n (messages.properties) ou um texto contendo a informação sobre a lógica anotada, sendo este apresentado para o administrador do sistema durante a delegação de qual usuário terá ou não acesso
pageAccessDenied= Aqui seria informado uma página para direcionamento,c aso o usuário logado não tenha direitos de acesso.
messageAccessDenied= Aqui seria informado uma chave do arquivo i18n ou um texto contendo a mensagem de negação.

Seria legal também se a classe pudesse receber uma outra anotação, ex: @ResourceControl(description=“Relatórios”), onde seria informado um texto ou chave i18n para facilitar na organização do administrador do sistema, onde as lógicas anotada como segurança ficariam agrupadas dentro dos seus respectivos recurso (classes) e com isso teríamos uma arvore de controle de acesso.

Com isso teríamos o seguinte modelo HTML

Relatórios
|
±–> Relatório gerencial
+…
+…
±–> Relatório administrativo

E o administrador selecionaria os métodos “anotados” e daria o direito de acesso ao usuário, também selecionado…

Dá para ir mais a fundo nestas ideias, o importante é que o teu modelo fica mais flexível, pois o desenvolvedor não precisa saber qual a regra para cada método anotado, isto fica a cardo do administrador.

Abraços.

[quote=softwork]Amigo boneazul!
Eu gostei muito do teu modelo para controlar o acesso e segurança, porém acredito que ficaria muito melhor se você utilizar o nome do método anotado ao invés de uma Ação numerada, pois assim o desenvolvedor não precisaria se preocupa em saber qual ação deverá ser associada ao método/lógica, mas ficaria bastante elegante se na anotação @VerifyAccess pudesse informar 3 parâmetros, onde:

@VerifyAccess(description=“Relatório gerencial|Esta lógica serve para imprimir o relatório gerencial.”,
pageAccessDenied="/acessoNegado.jsp",
messageAccessDenied=“acesso.negado”
)

Sendo assim:
description= Aqui seria informado uma chave do arquivo i18n (messages.properties) ou um texto contendo a informação sobre a lógica anotada, sendo este apresentado para o administrador do sistema durante a delegação de qual usuário terá ou não acesso
pageAccessDenied= Aqui seria informado uma página para direcionamento,c aso o usuário logado não tenha direitos de acesso.
messageAccessDenied= Aqui seria informado uma chave do arquivo i18n ou um texto contendo a mensagem de negação.

Seria legal também se a classe pudesse receber uma outra anotação, ex: @ResourceControl(description=“Relatórios”), onde seria informado um texto ou chave i18n para facilitar na organização do administrador do sistema, onde as lógicas anotada como segurança ficariam agrupadas dentro dos seus respectivos recurso (classes) e com isso teríamos uma arvore de controle de acesso.

Com isso teríamos o seguinte modelo HTML

Relatórios
|
±–> Relatório gerencial
+…
+…
±–> Relatório administrativo

E o administrador selecionaria os métodos “anotados” e daria o direito de acesso ao usuário, também selecionado…

Dá para ir mais a fundo nestas ideias, o importante é que o teu modelo fica mais flexível, pois o desenvolvedor não precisa saber qual a regra para cada método anotado, isto fica a cardo do administrador.

Abraços.
[/quote]

É o mais “legal” da ideia tirando a porquisse dos ids é essa flexibilidade mesmo, de tirar da mão do programador o que cada pessoa deve acessar , ao meu ver não tem o porque disso.

Digamos que esse modelo do bronx é role-based e o meu seria um action-based …

a diferenca entre os dois é que o dele é bem mais simples pois não é necessario geração de banco para controle apenas uma list de roles do usuario,porém como nada é perfeito peca na parte de manutenção pois se algum ou varios metodos mudam de perfil teria que ir em código mudar e isso num é legal.

o meu é mais complexo pois ha geração de banco pra controle ,mapeamento de ações do sistema porém o sistema fica totalmente desacoplado do programador pois que define o que o perfil pode fazer é o proprio gerente,administrador,supervisor …

não tive tempo ainda de pensar em algo pra melhorar akeles ids,poderia ser ligado sim a string em vez do id mas ai teria mapeamento do mesmo modo ou seja do mapeamento de ações não teria como fugir

O ideal seria realmente algo do tipo

@VerifyAcess("listaUsuario")
public void lista(){
.........
}

Eu utilizo esse eskema de “Assunto da ação” tipo,isso torna muito mais organizado para quem delega , só não postei pois aumenta 1 classe apenas

–Relatorios
—Imprimir relatorio compra
—Imprimir relatorio venda
–Cadastros
—Lista vendedor
—Editar vendedor
—Desativar vendedor
.
.
.

os outros parametros nem seriam necessarios creio eu, pois geralmente voce num tem muito o que falar apenas : “Acesso negado,voce não tem permissão para executar essa operação” tipo uma frase meio que genérico ja resolveria bem.Nada que um interceptor não resolva.

Vo pensar em algo mais programatico é que estou sem tempo pra fazer algo mais elegante.
Pois estou trabalhando em outra contribuição muito maior pra turma do Vraptor, que garanto o pessoal vai gostar bastante.

O trabalho que o bronx esta fazendo é genial e de fato é mais simples, basta apenas no momento de LOGIN carregar a lista de regras/perfis deste usuário, mas o problema é se uma gerente de negócio mudar o escopo de segurança, ou seja, uma lógica que foi anotada para ter acesso somente ao gerente e ao usuário, agora passe a ter também um supervisor, então eu teria que ir no código para fazer isso e em seguida fazer um “deploy” e colocar para teste e só depois se homologado, colocar em produção.
Se este “foco” mudar, o modelo ficará perfeito.

Pois é amigo, apesar do teu código ter a “complexidade” de 2 ou 3 entidades no banco e um trabalho de delegação de acesso por parte de um chefe de setor, gerente ou supervisor é esta a realidade na maioria das empresas, pois o escopo sempre muda, sempre irá existir a dinâmica para cada usuário ou um determinado perfil.
Bom, pelo menos aqui na FAESP “Federação da Agricultura e Pecuária do Estado de São Paulo” e SENAR "Serviço Nacional de Aprendizagem Rural, ambas sem fins lucrativos, sempre há mudanças.

Então boneazul, apesar da necessidade da entidade “ações”, acho que o foco seria um pouco diferente, pois a chave seria o nome do método e para não apresentar algo “estranho” para o administrador de segurança (ex: listaUsuario) seria interessante apresentar um texto “breve” explicativo, algo como: Lista de Usuários, sendo assim a anotação iria buscar no aquivo de properties a mensagem a ser apresentada ao administrador, porém acho que falta um direcionamento para uma página de “acesso negado”, pois se um usuário logado tentar acessar o método anotado e este não tiver direito de acesso, ele deverá ser direcionado para uma mensagem padrão ou uma específica, conforma a necessidade do desenvolvedor.

Mas acho que poderia seguir a linha de convenção do vRaptor, ou seja, no arquivo de properties teríamos a chave: lista.texto = Lista de Usuários (mensagem para o administrador) e para o direcionamento, caso não informado na anotação, seria algo assim: /[classe].[método].negado.jsp

Situação simples:

@VerifyAcess()
public void lista(){
.........
}

Situação específica:

@VerifyAcess(pageAccessDenied="/acessoNegado.jsp")
public void lista(){
.........
}

ou

@VerifyAcess(description="listaDeUsuarios.texto", pageAccessDenied="/acessoNegado.jsp")
public void lista(){
.........
}

Acho de dá para pensar ainda mais sobre o assunto.

Bom, parabéns para o bronx e ao boneazul pela iniciativa e principalmente pela contribuição para a comunidade.

Muito obrigado aos dois.

Sem dúvidas é uma excelente contribuição. Tenho acompanhado o tópico, mesmo sem opiniar muito, e posso dizer que é uma excelente contribuição. Certamente facilita muito o uso, porém o diferencial é a integração transparente ao vraptor, já que soluções como jaas e acegy tem de serem feitas na mão.

Abraços, e obrigado por compartilharem.

[quote=softwork][quote=boneazul]
a diferenca entre os dois é que o dele é bem mais simples pois não é necessario geração de banco para controle apenas uma list de roles do usuario,porém como nada é perfeito peca na parte de manutenção pois se algum ou varios metodos mudam de perfil teria que ir em código mudar e isso num é legal.
[/quote]

O trabalho que o bronx esta fazendo é genial e de fato é mais simples, basta apenas no momento de LOGIN carregar a lista de regras/perfis deste usuário, mas o problema é se uma gerente de negócio mudar o escopo de segurança, ou seja, uma lógica que foi anotada para ter acesso somente ao gerente e ao usuário, agora passe a ter também um supervisor, então eu teria que ir no código para fazer isso e em seguida fazer um “deploy” e colocar para teste e só depois se homologado, colocar em produção.
Se este “foco” mudar, o modelo ficará perfeito.

Pois é amigo, apesar do teu código ter a “complexidade” de 2 ou 3 entidades no banco e um trabalho de delegação de acesso por parte de um chefe de setor, gerente ou supervisor é esta a realidade na maioria das empresas, pois o escopo sempre muda, sempre irá existir a dinâmica para cada usuário ou um determinado perfil.
Bom, pelo menos aqui na FAESP “Federação da Agricultura e Pecuária do Estado de São Paulo” e SENAR "Serviço Nacional de Aprendizagem Rural, ambas sem fins lucrativos, sempre há mudanças.

Então boneazul, apesar da necessidade da entidade “ações”, acho que o foco seria um pouco diferente, pois a chave seria o nome do método e para não apresentar algo “estranho” para o administrador de segurança (ex: listaUsuario) seria interessante apresentar um texto “breve” explicativo, algo como: Lista de Usuários, sendo assim a anotação iria buscar no aquivo de properties a mensagem a ser apresentada ao administrador, porém acho que falta um direcionamento para uma página de “acesso negado”, pois se um usuário logado tentar acessar o método anotado e este não tiver direito de acesso, ele deverá ser direcionado para uma mensagem padrão ou uma específica, conforma a necessidade do desenvolvedor.

Mas acho que poderia seguir a linha de convenção do vRaptor, ou seja, no arquivo de properties teríamos a chave: lista.texto = Lista de Usuários (mensagem para o administrador) e para o direcionamento, caso não informado na anotação, seria algo assim: /[classe].[método].negado.jsp

Situação simples:

@VerifyAcess()
public void lista(){
.........
}

Situação específica:

@VerifyAcess(pageAccessDenied="/acessoNegado.jsp")
public void lista(){
.........
}

ou

@VerifyAcess(description="listaDeUsuarios.texto", pageAccessDenied="/acessoNegado.jsp")
public void lista(){
.........
}

Acho de dá para pensar ainda mais sobre o assunto.

Bom, parabéns para o bronx e ao boneazul pela iniciativa e principalmente pela contribuição para a comunidade.

Muito obrigado aos dois.
[/quote]

“e um trabalho de delegação de acesso por parte de um chefe de setor, gerente ou supervisor é esta a realidade na maioria das empresas, pois o escopo sempre muda, sempre irá existir a dinâmica para cada usuário ou um determinado perfil.”

É realmente ,por exemplo para a minha empresa, modelo de ROLES não rola e por isso nem é adotado.
Se voce ta falando que na sua tem 2 já somos 3 que esse tipo de implementação fica inviavel.
Pois isso postei a alternativa.

então talvez voce não tenha entendido bem o meu modelo cara,pelas sugestões que está me passando

Vo tentar ser simples na explicação do interior da parada.

No geral vai ser 4 tabelas
perfil,acesso,acoes,categoriaacoes


Tabela categoriaacoes :

Guarda as categorias de ações pra ficar mais organizado na interface do usuario ,que foi o que voce dissse uns posts atras

-Relatórios Gerencias
-Relatórios Administrativos
.
.

Tabela ações

Guarda todas as ações mapeadas no seu sistema e tem uma categoria listada acima

  • imprimir relatorio A - Relatórios Gerencias
  • imprimir relatorio B - Relatórios Gerencias
  • imprimir relatorio A - Relatórios Administrativos
  • imprimir relatorio B - Relatórios Administrativos

Nessa tabela o que poderia ser feito é passado a convenção ai ficaria legal

tipo a classe de acao seria

Id | Descrição da ação | Categoria da acao | Convenção que segue

1 | imprimir relatorio A | 1 | /vendedor/lista

dai dai pra fazer algo do tipo que voce necessita

Ai daria pra ver …

O método de acesso tem anotação??
Se tem anotação ,eu busco o usuario na sessao pego seu perfil pego as ações ligada ao perfil e procuro a convenção ,se ela não existe então negaria o acesso ao recurso caso exista deixaria acessar.
Quanto as outras configurações ficaria facil.

Algumas ate desnecessario exemplo a i18n com a key como voce sugerir sendo ja que voce so poderia passar a logica a executar
isso no final iria renderizar um jsp ai no jsp voce usaria a i18n com tag lib <c ou <fmt num lembro

quanto ao seu pageAccessDenied="/acessoNegado.jsp" nao sei se seria necessario pois ai seria generalização demais sendo que todas vez ele seguiria isso ficaria meio estranho de ver poderia deixar alguma pagina generica e caso ele passasse alguma lógica ai executaria a lógica ,não é o meu caso pois como disse eu sempre uso uma frase genérica “Voce não tem direito de acesso a esse recurso” pois seria até improdutivo fazer um jsp pra cada logica negada so pra mudar algumas palavras tipo
"Voce não tem permissao para ‘key’"

Pois há outros lados tamem , eu não mostro nada pra clicar se o cara ja nao tem acesso …

Exemplo… não se mostra uma aba que o cara num pode acessar,não se mostra um link de inserir se ele não insere o sistema TEM que se modelar ao perfil ou seja some ou aparece com as coisas isso pensando na view e se ele ta tentando acessar algo que não deve com certeza está forçando na url no meu caso. Tanto é que eu sempre guardo o usuario engraçadinho pra saber que ta tentando acessar por url direto e se precisar notificar.
Já aconteceu caso.Os caras da minha empresa são bem chato sem relação a autenticação e auditoria nesse sentido.
Pois minhas classes já são adaptadas pra auditoria também tipo desde o que o cara loga ate sair eu sei o que ele fez.Acontecia muito de usuario dizer.

“Sumiu aqui.não fui eu quem apagou” ai eu " apagou sim , apagou dia … hora minuto em segundo que ele fez" , antigamente ficava a responsabilidade pra gente.É aquele negócio cada projeto tem suas necessidades.Eu sempre preciso garantir certas coisas que são boas práticas.Essa são exemplos reais que sempre enfrentei.

vo dar uma pensada em algo simples pra ficar nesse modo com algumas customizações…

@VerifyAcess()
public void lista(){

}

Abraços a todos.