Autenticação e Autorização
A segurança de uma aplicação pode ser dividida em duas partes: autenticação e autorização. A autenticação é o processo de identificação do usuário. Geralmente, através de uma tela onde o usuário fornece seu login e senha. Autorização é o processo onde o sistema verifica se determinado usuário possui permissão para acessar alguma funcionalidade do sistema. O NEO possui suporte apenas para a implementação do processo de autorização, que é o processo mais complicado. Uma das formas de se implementar a autorização é utilizando JAAS. O NEO detecta se algum login foi feito utilizando JAAS, então nenhum trabalho extra é necessário. Como a configuração via JAAS muda de servidor para servidor, mostraremos um exemplo 'manual' de autenticação. Como a autenticação e autorização andam juntas, vamos implementar as duas ao mesmo tempo. Para o processo de autorização o NEO necessita que algumas interfaces sejam implementadas, são elas: - User: POJO que representa um usuário no sistema - Role: POJO que representa um papel (ou nível) no sistema - Permission: POJO que representa a permissão de determinado papel para determinado controller do sistema - AuthorizationDAO: DAO que fornece métodos para descobrir informações sobre a autorização Essas interfaces não definem nenhum relacionamento entre User e Role. Esse relacionamento é definido na aplicação, da forma que o desenvolvedor desejar. Não é necessário que os POJOs sejam entidades do Hibernate. Mas como nossos dados estão em um banco de dados, aproveitaremos o bean para fazer o mapeamento no banco de dados. Um exemplo de implementação para essas interfaces seria o seguinte:
package entity;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;

import br.com.linkcom.neo.authorization.User;
import br.com.linkcom.neo.bean.annotation.DescriptionProperty;
import br.com.linkcom.neo.types.Password;

/**
 * Representa um usuário no sistema
 */
@Entity
public class Usuario implements User {
	
	Integer id;
	String nome;
	String login;
	String password;
	
	@Id
	@GeneratedValue
	public Integer getId() {
		return id;
	}
	//API
	public String getLogin() {
		return login;
	}
	
	@DescriptionProperty
	public String getNome() {
		return nome;
	}
	
	//API
	@Password
	public String getPassword() {
		return password;
	}
	public void setId(Integer id) {
		this.id = id;
	}
	public void setLogin(String login) {
		this.login = login;
	}
	public void setNome(String nome) {
		this.nome = nome;
	}
	public void setPassword(String password) {
		this.password = password;
	}



}

package entity;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;

import br.com.linkcom.neo.authorization.Role;
import br.com.linkcom.neo.bean.annotation.DescriptionProperty;

/**
 * Representa um papel no sistema, um nível de permissão.
 * Ex.: Administrador, Usuário, Financeiro
 */
@Entity
public class Papel implements Role {
	
	Integer id;
	String description;
	String name;
	
	@Id
	@GeneratedValue
	public Integer getId() {
		return id;
	}
	
	//API
	@DescriptionProperty
	public String getDescription() {
		return description;
	}
	
	//API
	public String getName() {
		return name;
	}
	public void setDescription(String description) {
		this.description = description;
	}
	public void setId(Integer id) {
		this.id = id;
	}
	public void setName(String name) {
		this.name = name;
	}



}

package entity;

import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;

import br.com.linkcom.neo.authorization.impl.AbstractPermission;

/**
 * Representa a permissão para determinado papel em determinada tela
 */
@Entity
public class Permissao extends AbstractPermission {
	
	Integer id;
	Papel role;
	String permissionString;
	String path;
	
	@Id
	@GeneratedValue
	public Integer getId() {
		return id;
	}
	public String getPath() {
		return path;
	}
	
	//API
	public String getPermissionString() {
		return permissionString;
	}
	
	//API
	@ManyToOne(fetch=FetchType.LAZY)
	@JoinColumn(name="role_id")
	public Papel getRole() {
		return role;
	}
	public void setId(Integer id) {
		this.id = id;
	}
	public void setPath(String path) {
		this.path = path;
	}
	public void setPermissionString(String permissionString) {
		this.permissionString = permissionString;
	}
	public void setRole(Papel role) {
		this.role = role;
	}

}

package dao;

import java.util.List;
import java.util.Map;

import org.springframework.orm.hibernate3.HibernateTemplate;

import entity.Papel;
import entity.Permissao;
import entity.Usuario;
import entity.UsuarioPapel;

import br.com.linkcom.neo.authorization.AuthorizationDAO;
import br.com.linkcom.neo.authorization.Permission;
import br.com.linkcom.neo.authorization.Role;
import br.com.linkcom.neo.authorization.User;
import br.com.linkcom.neo.persistence.QueryBuilder;

/**
 * DAO de autorização, detectado automaticamente pelo NEO.
 * Fornece informações sobre autorização para o framework 
 */
public class NeoAuthorizationDAO implements AuthorizationDAO {
	
	private HibernateTemplate hibernateTemplate;
	
	public void setHibernateTemplate(HibernateTemplate hibernateTemplate) {
		this.hibernateTemplate = hibernateTemplate;
	}
	
	//API
	/**
	 * Retorna a lista de todos os papeis do sistema
	 */
	public Role[] findAllRoles() {
		List roles = new QueryBuilder(hibernateTemplate)
							.from(Papel.class)
							.list();
		return roles.toArray(new Role[roles.size()]);
	}

	//API
	/**
	 * Acha a permissão para determinado nível em determinada tela
	 * @param role papel que desejamos a permissão
	 * @param controlName path que representa a tela desejada
	 */
	public Permission findPermission(Role role, String controlName) {
		return new QueryBuilder(hibernateTemplate)
					.from(Permissao.class)
					.where("permissao.role = ?", role)
					.where("permissao.path = ?", controlName)
					.unique();
	}

	//API
	/**
	 * Acha o usuário pelo login
	 */
	public User findUserByLogin(String login) {
		return new QueryBuilder(hibernateTemplate)
					.from(Usuario.class)
					.where("usuario.login = ?", login)
					.unique();
	}

	//API
	/**
	 * Acha os papeis (níveis) de determinado usuário
	 */
	public Role[] findUserRoles(User user) {
		List list = new QueryBuilder(hibernateTemplate)
							.select("papel")
							.from(UsuarioPapel.class)
							.leftOuterJoin("usuarioPapel.papel papel")
							.leftOuterJoin("usuarioPapel.usuario usuario")
							.where("usuario = ?", user)
							.list();
		return list.toArray(new Role[list.size()]);
	}
	
	//API
	/**
	 * Salva ou atualiza uma permissão no banco de dados.
	 */
	public Permission savePermission(String controlName, Role role, Map permissionMap) {
		Permissao permissao = (Permissao)findPermission(role, controlName);
		if(permissao == null){
			permissao = new Permissao();
			permissao.setPath(controlName);
			permissao.setRole((Papel) role);
		}
		permissao.setPermissionMap(permissionMap);
		hibernateTemplate.saveOrUpdate(permissao);
		return permissao;
	}

}

Note que foi utilizado um bean extra, UsuarioPapel, para fazer o relacionamento entre user e role. Esse bean é apenas um bean de ligação, para fazer um relacionamento muitos para muitos.
package entity;

import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.ManyToOne;

/**
 * Faz o relacionamento entre Usuário e Papel
 * Relacionamento muitos para muitos entre usuario e papel
 */
@Entity
public class UsuarioPapel {

	Integer id;
	Usuario usuario;
	Papel papel;
	
	@Id
	@GeneratedValue
	public Integer getId() {
		return id;
	}
	
	@ManyToOne(fetch=FetchType.LAZY)
	public Papel getPapel() {
		return papel;
	}
	
	@ManyToOne(fetch=FetchType.LAZY)
	public Usuario getUsuario() {
		return usuario;
	}
	public void setId(Integer id) {
		this.id = id;
	}
	public void setPapel(Papel papel) {
		this.papel = papel;
	}
	public void setUsuario(Usuario usuario) {
		this.usuario = usuario;
	}
}

Esses beans são entidades no banco de dados e também representam informações para o processo de autorização. O NEO irá detectar qualquer classe que implemente AuthorizationDAO na aplicação, não coloque @Bean nessa classe. Essa classe pode ficar em qualquer pacote e ter qualquer nome. Essas classes ainda não tem efeito de autorização nenhum na aplicação, uma vez que nenhum controller foi configurado com autorização. Antes de prosseguirmos com a autorização vamos criar o processo de autenticação. Crie na aplicação um novo módulo do NEO. Esse módulo, no exemplo desse tutorial irá se chamar secured. Para criar um módulo do neo é necessário um DispatcherServlet, no nosso caso para a URL /secured/* no web.xml. Criar o diretório /WEB-INF/jsp/secured. E colocar um arquivo base.jsp em /WEB-INF/jsp/secured. Vamos criar um filtro que apenas usuários logados no sistema possam acessar esse módulo. Crie o filtro conforme o modelo:
package filter;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

import br.com.linkcom.neo.core.standard.Neo;

public class AuthenticationFilter implements Filter {

	String loginPage = "/modulo/login";

	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
		if(Neo.getUser() == null){
			request.getRequestDispatcher(loginPage)
						.forward(request, response);
		} else {
			chain.doFilter(request, response);
		}
	}

	public void destroy() {
	}
	public void init(FilterConfig config) throws ServletException {
	}

}

O authenticationFilter irá redirecionar para um controller caso não exista usuário no sistema, o código desse controller é o seguinte:
package controller;

import org.springframework.web.servlet.ModelAndView;

import dao.NeoAuthorizationDAO;

import entity.Usuario;

import br.com.linkcom.neo.authorization.User;
import br.com.linkcom.neo.controller.Controller;
import br.com.linkcom.neo.controller.DefaultAction;
import br.com.linkcom.neo.controller.MessageType;
import br.com.linkcom.neo.controller.MultiActionController;
import br.com.linkcom.neo.core.web.WebRequestContext;
import br.com.linkcom.neo.view.menu.MenuTag;

/**
 * Controller que fará o login do usuário na aplicação.
 * Se o login for efetuado com sucesso irá redirecionar para /secured/Index
 */
@Controller(path="/modulo/login")
public class LoginController extends MultiActionController {

	private static final String AFTER_LOGIN_GO_TO = "/secured/Index";
	
	NeoAuthorizationDAO authorizationDAO;
	
	public void setAuthorizationDAO(NeoAuthorizationDAO authorizationDAO) {
		this.authorizationDAO = authorizationDAO;
	}
	
	/**
	 * Action que envia para a página de login
	 */
	@DefaultAction
	public ModelAndView doPage(WebRequestContext request, Usuario usuario){
		return new ModelAndView("login", "usuario", usuario);
	}
	
	/**
	 * Efetua o login do usuário
	 */
	public ModelAndView doLogin(WebRequestContext request, Usuario usuario){
		String login = usuario.getLogin();
		//se foi passado o login na requisição, iremos verificar se o usuário existe e a senha está correta
		if(login != null){
			//buscamos o usuário do banco pelo login
			User userByLogin = authorizationDAO.findUserByLogin(login);
			
			// se o usuário existe e a senha está correta
			if(userByLogin != null && userByLogin.getPassword().equals(usuario.getPassword())){
				//Setando o atributo de seção USER fazemos o login do usuário no sistema. 
				request.setUserAttribute("USER", userByLogin);
				
				//Limpamos o cache de permissões o menu.
				//O menu será refeito levando em consideração as permissões do usuário
				request.setUserAttribute(MenuTag.MENU_CACHE_MAP, null);
				return new ModelAndView("redirect:"+AFTER_LOGIN_GO_TO);				
			}
			
			//Se o login e/ou a senha não estiverem corretos, avisar o usuário
			request.addMessage("Login e/ou senha inválidos", MessageType.ERROR);
		}
		
		//limpar o campo senha, e enviar para a tela de login já que o processo falhou
		usuario.setPassword(null);
		return doPage(request, usuario);
	}
}

e o login.jsp
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix="n" uri="neo"%>
<%@ taglib prefix="t" uri="template"%>

<n:form>
<n:bean name="usuario">
	<t:propertyConfig renderAs="double" mode="input">
	<n:panelGrid 
			columns="2" 
			align="center" 
			style="width: 180px; background-color: #F8F4EA; padding:2px; border: 1px solid #949087" 
			columnStyles="font-size: 12px;">
		<n:panel style="background-color:#6699CC; color:white; font-weight:bold" colspan="2">
			Login
		</n:panel>
		<t:property name="login"/>
		<t:property name="password" label="Senha"/>
		<n:submit action="doLogin" panelColspan="2" panelAlign="right">Enviar</n:submit>
	</n:panelGrid>
	</t:propertyConfig>
</n:bean>
</n:form>
Após criar as classes devemos registrar dois filtros no web.xml. O filtro de autenticação (o que criamos) e o filtro de autorização (fornecido pelo NEO).
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4" 
	xmlns="http://java.sun.com/xml/ns/j2ee" 
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
	xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee 
	http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
	
	<!-- Listener que inicializa a aplicação -->
    <listener>
        <listener-class>br.com.linkcom.neo.core.web.init.ContextLoaderListener</listener-class>
    </listener>
    
   	<!-- Filtro para criar o contexto do NEO -->
   	<filter>
		<filter-name>neoFilter</filter-name>
		<filter-class>br.com.linkcom.neo.core.web.NeoFilter</filter-class>
	</filter>
	<filter-mapping>
		<filter-name>neoFilter</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>

	<!-- Filtro de autenticação. Verifica se o usuário está logado -->
   	<filter>
		<filter-name>authenticationFilter</filter-name>
		<filter-class>filter.AuthenticationFilter</filter-class>
	</filter>

	<!-- Esse filtro irá barrar todo acesso anonimo à /secured/* -->
	<!-- Se desejar barrar acesso anonimo à outras URLs duplique o filter-mapping e altere a url-pattern -->
	<filter-mapping>
		<filter-name>authenticationFilter</filter-name>
		<url-pattern>/secured/*</url-pattern>
	</filter-mapping>
	
	<!-- Filtro de autorização, verifica as permissões para determinado recurso -->
	<filter>
		<filter-name>authorizationFilter</filter-name>
		<filter-class>br.com.linkcom.neo.authorization.AuthorizationFilter</filter-class>
	</filter>
	<filter-mapping>
		<filter-name>authorizationFilter</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>
	

	<!-- Servlet necessário para Ajax -->	
	<servlet>
		<servlet-name>ajaxServlet</servlet-name>
		<servlet-class>br.com.linkcom.neo.view.AjaxServlet</servlet-class>
	</servlet>
	<servlet-mapping>
		<servlet-name>ajaxServlet</servlet-name>
		<url-pattern>/ajax/*</url-pattern>
	</servlet-mapping>
	
	<!-- Servlet necessário do NEO, provê JS e CSS -->
    <servlet>
        <servlet-name>resourceServlet</servlet-name>
        <servlet-class>br.com.linkcom.neo.view.ResourceServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>resourceServlet</servlet-name>
        <url-pattern>/resource/*</url-pattern>
    </servlet-mapping> 	
    
    <!-- Servlet necessário para os inputs select-one-path e select-one-button -->
    <servlet>
        <servlet-name>selecionarCadastrarServlet</servlet-name>
        <servlet-class>br.com.linkcom.neo.view.SelecionarCadastrarServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>selecionarCadastrarServlet</servlet-name>
        <url-pattern>/SELECIONARCADASTRAR/*</url-pattern>
    </servlet-mapping> 	
    
    
    <!-- Módulo da aplicação -->
    <servlet>
        <servlet-name>modulo</servlet-name>
        <servlet-class>br.com.linkcom.neo.controller.DispatcherServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>modulo</servlet-name>
        <url-pattern>/modulo/*</url-pattern>
    </servlet-mapping>
    
    
    <!-- Módulo seguro da aplicação, só é possível acessar esse módulo se o usuário tiver logado no sistema -->
    <servlet>
        <servlet-name>secured</servlet-name>
        <servlet-class>br.com.linkcom.neo.controller.DispatcherServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>secured</servlet-name>
        <url-pattern>/secured/*</url-pattern>
    </servlet-mapping>
    

    	
</web-app>

A ordem dos filtros deve ser seguida. Primeiro vem o neoFilter, depois o authenticationFilter e depois o authorizationFilter. Nesse momento se quisermos acessar qualquer recurso dentro de /secured o authenticationFilter irá interceptar a requisição e enviar o usuário para a tela de login até que o usuário esteja logado no sistema. O LoginController após logar o usuário no sistema faz o redirecionamento para /secured/Index. Mas poderia ser para qualquer outro controller. Lembre-se de implementar um controller para receber a requisição após o login no sistema.
Tutoriais
Últimas postagens
Alguem ainda usa o NEO? Autor: Nunes sem hibernate Autor: csilva2001 Erro ao fazer update [RESOLVIDO] Autor: Tchaco Erro CrudController Autor: edu_fernandes Artigos, Livros e documentação Autor: Nunes Crud Master Detail Autor: carlos ribeiro [RESOLVIDO] Problema ao iniciar aplicação com NEO Autor: R.Albany gerar relatórios Autor: mouzer [RESOLVIDO] Missing required Java project: 'Neo' Autor: r3n4n The method ognl(String) in the type NeoFunctions is not applicable for the arguments () Autor: r3n4n Dúvida com videos em flash e jsp Autor: thiago cassimiro Criptografar senhas Postgresql Autor: labavel Fazer upload da imagem em disco e no banco Autor: labavel Estilo no detalhe Autor: Tchaco Acessar o equivalente ao Neo.getUser() dentro da JSP Autor: konkix Dúvida de iniciante Autor: Eder Acesso a banco de dados Autor: Nunes Gravar Imagem no Banco Autor: Tchaco Campos AUTOCOMPLETE Autor: vanessa Assinatura Digital Autor: biharck Projeto NEO pode ser utilizado em um grande cliente do grande ABC. Autor: Nunes Layout Mestre Detalhe Autor: viniciusst Problemas com o type CPFCNPJ Autor: viniciusst Combo de Estado Autor: viniciusst Suporte a dois SGBD's Simultâneos Autor: biharck Many-to-Many Autor: Tux Gerando relatórios Autor: viniciusst Problemas com filtro listagem Autor: vberga Projeto descontinuado Autor: viniciusst Crud com erro - MySQL Autor: viniciusst Erro de cast no DAO Autor: biharck @DescriptionProperty Multiplos Autor: joaopedro Geração de tabelas - CRUD Autor: Nunes iReport Autor: jlevi Impressão de PDF em Bamatech MP20-MI Autor: Alisson Retorno - Novidades Autor: vinicius.janones CRUD Avançado Autor: cassioseffrin CRUD Autor: miltonmmjr Upload Multiplo de Imagem Autor: robmsjr Problema com anotação Autor: tulio Integração com Hibernate Autor: Nunes Dúvida quanto à referência a imagens Autor: mmfalcao Problema com atributo do tipo byte[] Autor: tulio Relacionamento Many to Many Autor: LeonardoBH Problema ao subir aplicação de upload de arquivos Autor: cassioseffrin Neo versão 3.4.0 Autor: pedro.goncalves Problemas neo 3.4 + jboss 5 e Cascade no Hibernate Autor: vberga Erro ao anotar @Bean Autor: edson.goncalez Suporte a paginação Autor: int80h Menu vertical Autor: fabricio.costa