Permissão de Acesso em Swing

Olá a todos amigos do forum. Estou definindo padrões para o desenvolvimento de um software que será migrado de Delphi para Java. No sistema em Delphi as permissões dos usuários são definidas no campos de um formulário, por exemplo, num sistema de consulta de clientes, eu posso definir quais campos um vendedor pode ver, quais um gerente pode ver, etc. No sistema em Java deverá possuir a mesma funcionalidade, ai é que está o problema, se eu, no momento de criar a interface gráfica, verificar componente por componente se o usuário ter permissão de vê-lo ou não acho que o sistema não terá boa performance.

Vocês tem alguma sugestão do que pode ser feito para fazer estas verificações de permissão mantendo a boa performance do sistema?

Muito obrigado a todos e um feliz ano novo.

Pode dar mais um detalhe , é separado por componentes ou por campos ?

Por exemplo você pode fazer um JPanel com dados pra exibir no caso
de ser o gerente , senao apenas mostra os campos em comum…

Você vai ter que construir um “mini-framework” pra fazer isso e o pessoal
utilizar , nao é tao complicado tendo um bom conhecimento e sabendo
o que realmente deve ser feito…

Agora se o sistema for controlado “campo a campo” acho que optar
por uma solucao web é um caso a ser analisado , há muitos frameworks
que oferecem isso pra você prontinho , ( aka , mentawai , jsf , etc…)

Bom nada que um bom papo nao resolva qualquer duvida posta ae…
Boa sorte! :thumbup:

Não há como fazer em ambiente Web, o sistema é Desktop.

Sim, as permissões são definidas por campo (nome, endereço, etc.). É isto que está complicando (verificar campo por campo de maneira eficiente).

Fale um pouco mais sobre esta idéia do framework? Alguma idéia de como ele pode funcionar?

dá uma olhada neste link, … quem sabe pode te ajudar em alguma coisa …

http://java.sun.com/javase/6/docs/technotes/guides/security/jaas/tutorials/index.html

Obrigado, vou dar uma olhada aqui sim.

Não sabia que era possível utilizar JAAS sem um servidor de aplicações.
Vou ver se com JAAS é possível fazer o que desejo.

Qualquer dúvida pergunto aqui.

Alguém tem mais alguma sugestão de como posso resolver o problema?

Idéias são sempre bem vindas.

rapaz, perto do que eu estou para usar, seu problema pode ser na realidade uma solução, uma vez q eu vou ter que ver a mesma coisa.

por exemplo, se vc quiser fazer o componente literalmente desaparecer da tela se o usuário não puder mexer naquilo, é recomendável pensar na reestruturação de leiaute, etc. Mas se deixar disabled for opção, uma classe abstrata que 1- tenha uma implementação genérica de campos ou 2- obrigue cada janela a possuir uma certa implementação pode ser útil.

No meu caso, cada usuário tem uma “chave de acesso” (eh um número) e dependendo deste valor certas telas podem ou não serem vistas. mas aí se vc quiser alterações dinâmicas nos forms, bom, a coisa muda um pouco. nesse caso não somente as janelas, mas sim cada campinho, ao ser criado tem que ter uma “contra-chave” pra vc verificar se pode ou não isso ou aquilo.

no meu decidi pela simplicidade e estou usando números primos para definir os níveis de acesso. se, por exemplo, um usuário puder ter aceso a dois níveis distintos de segurança a chave deste cidadão é a multiplicação dos dois primos que representam tal funcionalidade.

se servir pra mim certamente postarei as dificuldades e alegrias de uso, blza?

boa sorte ae.

Eu optei pelo desenvolvimento de um pequeno Framework, visto que ele poderá ser facilmente utilizado, posteriormente, em outros projetos, sem contar que posso disponibilizá-lo como software livre.

Estou seguindo a seguinte idéia: tenho uma classe que herda JFrame e esta possui um método que verifica os componentes anotados para efetuar a validação. O problema que estou enfrentando parece ser simples, mas num pensei em nenhuma solução eficiente, somente em uma básica.

Ao buscar o Field, via reflection, eu preciso convertê-lo para sua classe padrão para definir suas propriedades, como posso fazer isto de maneira performática?

Eu fiz da seguinte forma:

		Object object = field.get(this);

		if (object instanceof JTextField) {
			JTextField jTextField = (JTextField) object;
			jTextField.setEditable(false);
		} else if (object instanceof JTextArea) {
			JTextArea jTextArea = (JTextArea) object;
			jTextArea.setEditable(false);
		} else if (object instanceof JCheckBox) {
			JCheckBox jCheckBox = (JCheckBox) object;
			jCheckBox.setEnabled(false);
		} else if (object instanceof JRadioButton) {
			JRadioButton jRadioButton = (JRadioButton) object;
			jRadioButton.setEnabled(false);
		}

Porém esta não me parece ser a melhor maneira. Alguém possui alguma sugestão de uma maneira mais eficiente para implementar o código?

Obrigado a todos.

Opa , esta surgindo uma solucao! :smiley:

Pense em classes “Abstratas” e “Implementacoes” feitas
por você do JTextField da JTextArea e assim por diante…

public class GujTextField extends JTextField{
 //No matter what happened it was not my fault.
}

Boa sorte! :thumbup:

Com isto poderia tornar o código mais eficiente? Me desculpe, mas não conseguir ver aonde você deseja chegar.
Poderia me dar mais alguns detalhes?

Para verificar as permissões do usuário, estarei fazendo, na minha classe que herda JFrame, um método abstrato que passa o nome do componente, ai nos meus formulários estará a implementação, visto que os objetos que armazenam as permissões somente estarão disponíveis lá. O que acha da solução? Alguma forma de melhorá-la?

Ricardo, vc pode usar uma fábrica de formulários.
Com essa fábrica, vc vai criar um layout para cada nível de usuáro de seu sistema.

Esse tutorial explica o uso de alguns design patterns, entre eles o Factory Method (que eu acredito que vá solucionar o seu problema)
http://www.guj.com.br/java.tutorial.artigo.137.1.guj

[quote=RicardoLuis]Com isto poderia tornar o código mais eficiente? Me desculpe, mas não conseguir ver aonde você deseja chegar.
Poderia me dar mais alguns detalhes?
[/quote]
Uhmn , estou apenas dando a ideia de você criar seus proprios componentes
assim você pode agregar novas funcionalidades a eles nao tendo que usar
JTextField aqui e GujTextField ali… sacou ? :wink:

Boa solução! Pode ser que exista alguma melhor , pode ser que não.
Bom tambem aceite a sugestao do Bernardo Rafael e de uma olhada
nos padrões de projeto que ele indicou quem sabe nao esta em algum
deles uma solucao talvez mais simples pro seu problema ?

Bernardo Rafael poderia dar uma breve explicada como poderia ser
utilizado estes padrões sugeridos para solucionar o problema?

Boa Sorte! :thumbup:

Na verdade, fazer a sua classe extender o JFrame não é uma boa…

Fazendo isso fará com que seu sistema fique dependente do JFrame e, se em algum momento vc desistir de usar swing para usar awt será um um parto.

O melhor mesmo é vc criar uma classe que monte a toda a tela e a mostre para o usuário.

Assim, se vc quiser mudar a API gráfica de seu sistema, ficará mais simples.

Olá,

Que tal em vez de usar classes abstratas para "obrigar"
a implementacao de um metodo porque nao utiliza uma
interface ? É uma saida muito mais elegante.

Boa Sorte! :thumbup:

Um exemplo de uso do Factory Method:

  • uma classe abstrata que serviria de base para as outras classes, no caso de uma janela, teriamos uma classe com o nome de ‘JanelaBase.java’
public abstract class JanelaBase {
   ... 
}
  • após isso, vc pode gerar quantas classes filhas de ‘JabelaBase’ quiser, por exemplo:
    1º - JanelaVendedor
public class JanelaVendedor extends JanelaBase {
   ...
   public JanelaVendedor(){
      ...
   }
}

2º - JanelaGerente

public class JanelaGerente extends JanelaBase {
   ...
   public JanelaGerente(){
      ...
   }
}
  • a partir deste momento, vc já pode começar a fabricar as suas janelas:
    JanelaFactory
public class JanelaFactory{
   public static final int JANELA_TIPO_VENDEDOR = 1;
   public static final int JANELA_TIPO_GERENTE = 2;

   public static JanelaBase getJanela(int tipo_janela){
      switch(tipo_janela){
      case JANELA_TIPO_VENDEDOR: return new JanelaVendedor();
      case JANELA_TIPO_GERENTE: return new JanelaGerente();
      default: return null;
      }
   }
}
  • aqui, é necessário tomar cuidado de mandar um tipo que possa ser fabricado, ou criar um tipo default para quando o tipo de Janela não for especificado corretamente.

espero que ajude.

Uhmn , no *“comeco da Thread” eu perguntei ao RicardoLuis se ele teria
que fazer o controle “campo-a-campo” ou poderia ser feito atraves de JPanel’s ele me respondeu que gostaria de controlar “campo-a-campo”…

Pois o sistema é altamente personalizavel em Delphi e ele gostaria de
fazer isso em Java tambem , acredito que “desenhar” uma janela pra cada tipo de usuario não é a melhor solução…

É , se fosse facil nao tinha graça. :stuck_out_tongue:
Valeu! :thumbup:

É exatamente este o X da questão, o sistema deve ser altamente personalizável, não podendo ser desenhada uma tela para cada permissão, visto que estas serão dinâmicas.

Eu devo fazer uma classe que implemente alguns métodos que determinarão os componentes da janela, porém esta classe será herdada pela minha janela, que já implementa JFrame. Realmente acho esta uma solução não muito elegante, mas ainda não pensei em uma maneira melhor de fazer. Seria possível fazer por composição? Alguma idéia?

Como dito acima, não pode ser feita uma tela para cada nível, é inviável. Em relação construir templates para as janelas o sistema será feito desta maneira, porém antes de tudo, o sistema de segurança já deve estar pronto.

No momento estou vendo uma forma de eliminar a depedência entre a classe base da segurança e JFrame, de forma a criar algo bem genérico, para ser utilizado como um framework.
Caso alguém tenha novas sugestões, eu agradeço.

Eu retirei a dependência de Jframe e adicionei a seguinte construtor:

public SwingSecurity(Window window) {
	super();
	this.window = window;
} /* Finaliza o construtor de objetos da classe SwingSecurity. */

Desta forma, é possível passar como parâmetro qualquer classe que herde de Window (JDialog, JFrame, etc). E em minha interface gráfica eu faço a chamada da seguinte forma:

new SwingSecurity(this).validateSecurity();

Porém, agora devo passar como parâmetro as permissões do usuário, mas não posso passar como parâmetro meu objeto usuário, pois isso geraria depêndencia. Pensei em passar um Map, onde a chave é o nome do campo e o valor é sua permissão.

Tá ficando abstrato demais , as ideias foram dadas.

Daqui pra frente eu vou conseguir entender melhor apenas se você colar codigo.

Boa Sorte! :thumbup:

Opa, não seja por isso :lol:

A classe até o momento está da seguinte forma:

/*
 * SwingSecurity.java
 *
 * Criado em 03 de Janeiro de 2006, 13h25
 */

package br.com.datamanager.security;

import java.awt.Window;
import java.lang.reflect.Field;
import java.util.Map;

import javax.swing.JComponent;
import javax.swing.JTextArea;
import javax.swing.JTextField;

import br.com.datamanager.security.annotation.VerifyObject;

/**
 * Classe que configura o nível de acesso de um usuário aos componentes visuais
 * de uma interface gráfica.
 *
 * Os componentes visuais são analisados, através de reflection, verificando se
 * os mesmos devem ser validados pelo sistema de segurança interno da aplicação
 * e, caso necessário, será realizada uma nova análise, para determinar o nível
 * de visualização do componente que o usuário tem acesso.
 *
 * Para a construção da classe o construtor recebe a interface gráfica que será
 * analisada e uma Hash Table com as permissões do usuário, sendo a chave desta
 * o nome do componente e o nível de permissão do usuário o seu valor.
 *
 * Para utilizar esta classe a aplicação cliente deve "anotar" seus componentes
 * visuais a serem validados com a anotação VerifyObject e executar uma chamada
 * ao método validateSecurity(java.awt.Window, java.util.Map<String, integer>),
 * como mostrado no exemplo:
 *
 *		new SwingSecurity(new JFrame(),
 *				new HashMap<String, Integer>()).validateSecurity();
 *
 * @author Ricardo Luís Fernandes Pinheiro
 * @version 1.0
 * @since 1.0
 *
 * @see br.com.datamanager.security.annotation.VerifyObject
 */
public class SwingSecurity implements Security {

	/** Interface gráfica que será validada pelo sistema de segurança. */
	private Window window;

	/**
	 * Objeto que armazena as permissões do usuário. A chave deste Map é o nome
	 * do componente visual e o valor é seu nível de acesso.
	 */
	private Map<String, Integer> permission;

	public SwingSecurity(Window window, Map<String, Integer> permission) {
		super();
		this.window = window;
		this.permission = permission;
	}

	public void validateSecurity() {

		for (Field field : window.getClass().getDeclaredFields()) {

			if (field.isAnnotationPresent(VerifyObject.class)) {
				field.setAccessible(true);

				if (permission.containsKey(field.getName())) {
					this.configureComponent(field, permission.get(field.getName()));
				} else {
					this.configureComponent(field, Security.ENABLE);
				}

			}

		}

	} /* Finaliza o método validateSecurity. */

	private void configureComponent(Field field, Integer status) {

		try {
			Object object = field.get(window);

			if (status.intValue() == Security.DISABLE.intValue()) {
				if (object instanceof JTextField) {
					JTextField jTextField = (JTextField) object;
					jTextField.setEditable(false);
				} else if (object instanceof JTextArea) {
					JTextArea jTextArea = (JTextArea) object;
					jTextArea.setEditable(false);
				} else {
					JComponent component = (JComponent) object;
					component.setEnabled(false);
				} /* Finaliza a estrutura condicional if/else. */
			} else if (status.intValue() == Security.HIDE.intValue()) {
				if (object instanceof JTextField) {
					JTextField jTextField = (JTextField) object;
					jTextField.setEditable(false);
					jTextField.setText("");
				} else if (object instanceof JTextArea) {
					JTextArea jTextArea = (JTextArea) object;
					jTextArea.setEditable(false);
					jTextArea.setText("");
				} else {
					JComponent component = (JComponent) object;
					component.setEnabled(false);
				} /* Finaliza a estrutura condicional if/else. */
			} else {
				if (object instanceof JTextField) {
					JTextField jTextField = (JTextField) object;
					jTextField.setEditable(true);
				} else if (object instanceof JTextArea) {
					JTextArea jTextArea = (JTextArea) object;
					jTextArea.setEditable(true);
				} else {
					JComponent component = (JComponent) object;
					component.setEnabled(true);
				}
			} /* Finaliza a estrutura condicional if/else. */
		} catch (IllegalArgumentException exception) {
			exception.printStackTrace();
		} catch (IllegalAccessException exception) {
			exception.printStackTrace();
		} /* Finaliza a estrutura de exceção try/catch. */

	}

} /* Finaliza a classe SwingSecurity. */

No momento estou trabalhando no método configureComponent, de modo a torná-lo mais eficiente, ele está muito poluído. Alguma idéia de como melhorá-lo?

Alguma sugestão de melhoria no mini-framework?