5
respostas

Login via JSF (joinFaces) com Spring Security

Como fazer login utilizando Form JSF e PrimeFaces no Spring Security

5 respostas

template.xhtml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
    xmlns:h="http://xmlns.jcp.org/jsf/html"
    xmlns:f="http://xmlns.jcp.org/jsf/core"
    xmlns:p="http://primefaces.org/ui"
    xmlns:pe="http://primefaces.org/ui/extensions"
    xmlns:ui="http://xmlns.jcp.org/jsf/facelets">
<h:head>
    <h:outputStylesheet library="webjars"
        name="primeflex/3.0.1/primeflex.min.css" />
</h:head>
<h:body>
    <pe:layout id="fullPage" stateCookie="true" widgetVar="fpLayoutWidget">
        <pe:layoutPane position="center" styleClassContent="conteudoPanel" spacingOpen="1">
            <!-- TOPO DA PAGINA -->
            <pe:layoutPane size="15%" position="north" styleClassContent="conteudoPanel" resizable="false" closable="false" spacingOpen="1">
                <p:commandButton type="button" icon="fa fa-fw fa-windows" onclick="PF('fpLayoutWidget').toggle('east')" style="position:absolute;right:10px;top:10px;" rendered="#{usuarioLogado != null}" />
                <ui:include src="header.xhtml" />

            </pe:layoutPane>

            <!-- CENTRO DA PAGINA -->
            <pe:layoutPane size="70%" position="center" styleClassContent="conteudoPanel" spacingOpen="1">

                <ui:insert name="centerContent">
                    Parte Central - Aonde vai a pagina xhtml a ser inserida
                </ui:insert>

            </pe:layoutPane>

            <!-- RODAPÉ DA PAGINA -->
            <pe:layoutPane size="15%" position="south" styleClassContent="conteudoPanel" resizable="false" closable="false" spacingOpen="1">
                Rodapé
            </pe:layoutPane>
        </pe:layoutPane>

        <!-- MENU DIREITO DA PAGINA -->
        <pe:layoutPane id="layoutPaneEast" position="east" styleClassContent="conteudoPanel" resizable="false" spacingOpen="1" spacingClosed="0">
            Painel à direita<br />
        </pe:layoutPane>
    </pe:layout>
</h:body>

</html>

login.xhtml

<?xml version="1.0" encoding="UTF-8" ?>
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
    xmlns:h="http://xmlns.jcp.org/jsf/html"
    xmlns:f="http://xmlns.jcp.org/jsf/core"
    xmlns:p="http://primefaces.org/ui"
    xmlns:pe="http://primefaces.org/ui/extensions"
    xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
    template="../../templates/template.xhtml">

    <ui:define name="centerContent">
        <script src='https://www.google.com/recaptcha/api.js'></script>
        <div class="flex align-items-center md:justify-content-center"
            style="min-height: 100%;">
            <h:form id="login" prependId="false">
                <p:growl showDetail="true" showSummary="true" globalOnly="true"
                    keepAlive="true" />
<!--                 <p:messages showDetail="true" showSummary="true" globalOnly="true" -->
<!--                     style="width:25rem;" /> -->
                <p:fieldset legend="Login">
                    <h:panelGrid columns="3">
                        <p:outputLabel value="Nickname:" for="nickname" />
                        <p:inputText id="nickname" value="#{loginBean.usuario.nickname}"
                            required="true" style="width:10rem;" />
                        <p:message for="nickname" id="messageNickname" />

                        <p:outputLabel value="Senha:" for="senha" />
                        <p:password id="senha" value="#{loginBean.usuario.senha}"
                            toggleMask="true" redisplay="true" feedback="true" inline="true"
                            required="true" style="width:10rem;" />
                        <p:message for="senha" id="messageSenha" />

<!--                         <p:outputLabel value="Captcha:" for="capthca" /> -->
<!--                         <p:captcha id="captcha" language="pt-BR" label="Captcha" -->
<!--                              rendered="true" /> -->
<!--                         <p:message for="capthca" id="messageCapthca" /> -->

                        <p:commandButton value="Efetue Login" type ="submit"
                            action="#{root}/login/process" update="@form" process="@form" />
                    </h:panelGrid>
                </p:fieldset>
            </h:form>
        </div>
    </ui:define>
</ui:composition>

LoginController.class

package br.com.coletadedados.controller;

import java.io.Serializable;

import javax.servlet.http.HttpServletRequest;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.context.annotation.RequestScope;

import br.com.coletadedados.controller.api.dto.request.UsuarioDTO;
import br.com.coletadedados.controller.dto.LoginDTO;
import br.com.coletadedados.service.UsuarioService;
import br.com.coletadedados.util.Mensagem;

@Controller(value = "loginBean")
@RequestScope
@RequestMapping("/login")
public class LoginController implements Serializable {

    private static final long serialVersionUID = 6273675035903617849L;

    private LoginDTO usuario = new LoginDTO();

    @Autowired
    private UsuarioService loginService;

    @GetMapping
    public String getPageLogin() {
        return "/pages/login/login.jsf";
    }

    @RequestMapping(value = "/process", method =  RequestMethod.POST)
    public void efetuaLogin(HttpServletRequest req, @RequestBody LoginDTO usuario) {
        System.out.println(usuario.getNickname());
        System.out.println(usuario.getSenha());
        try {
            loginService.autenticar(req, usuario);
            Mensagem.mensagemInformacao(null, SecurityContextHolder.getContext().getAuthentication().getPrincipal().toString(), "Login:");
        } catch (Exception e) {
            Mensagem.mensagemErro(null, e.getMessage(), "Erro ao efetuar login:");
            e.printStackTrace();
        }
    }

    public LoginDTO getUsuario() {
        return usuario;
    }

    public void setUsuario(LoginDTO usuario) {
        this.usuario = usuario;
    }
}

UsuarioService.class

package br.com.coletadedados.service;

import java.util.Optional;
import java.util.UUID;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.context.HttpSessionSecurityContextRepository;
import org.springframework.stereotype.Service;

import br.com.coletadedados.config.spring.autenticacao.CustomAuthenticationProvider;
import br.com.coletadedados.controller.api.dto.request.UsuarioDTO;
import br.com.coletadedados.controller.dto.LoginDTO;
import br.com.coletadedados.model.Usuario;
import br.com.coletadedados.repository.UsuarioRepository;
import br.com.coletadedados.service.singleton.LoogerService;

@Service("usuarioService")
public class UsuarioService {

    @Autowired
    private UsuarioRepository usuarioRepository;

    @Autowired
    private LoogerService logger;

    @Autowired
    private CustomAuthenticationProvider customAuthenticationProvider;

    public void autenticar(HttpServletRequest req, LoginDTO usuario) throws Exception {
        try {
            UsernamePasswordAuthenticationToken authReq = new UsernamePasswordAuthenticationToken(usuario.getNickname(),
                    usuario.getSenha());
            Authentication auth = this.customAuthenticationProvider.authenticate(authReq);
            SecurityContext sc = SecurityContextHolder.getContext();
            sc.setAuthentication(auth);
            HttpSession session = req.getSession(true);
            session.setAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY, sc);
        } catch (Exception e) {
            throw e;
        }
    }
}

SecurityConfiguration.class

package br.com.coletadedados.config.spring;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.access.channel.ChannelProcessingFilter;

import br.com.coletadedados.config.spring.autenticacao.AuthenticationFailureHandlerCuston;
import br.com.coletadedados.config.spring.autenticacao.CustomAuthenticationProvider;
import br.com.coletadedados.config.spring.filter.EncodingFilter;

@EnableWebSecurity
@Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Autowired
    private CustomAuthenticationProvider customAuthenticationProvider;

    //Configuracoes de autenticacao
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(customAuthenticationProvider);
    }

    //Configuracoes de autorizacao
    @Override
    protected void configure(HttpSecurity http) throws Exception {        
        http.csrf().disable()
        .authorizeRequests()
            .antMatchers("/login").permitAll()
            .anyRequest().authenticated()
        .and()
        .formLogin()
            .loginPage("/login")
            .usernameParameter("nickname")
            .passwordParameter("senha")
            .loginProcessingUrl("/login/process")
            .defaultSuccessUrl("/painelcontrol",true)
            .failureForwardUrl("/login?error")
            .failureHandler(authenticationFailureHandlerCuston)
            .permitAll()
        .and()
        .logout()
            .logoutUrl("/logout")
            .logoutSuccessUrl("/login?logout")
            .deleteCookies("auth_code", "JSESSIONID", "remember-me")
            .clearAuthentication(true)
            .invalidateHttpSession(true)
            .permitAll()
        .and()
        .sessionManagement()
            .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
        .exceptionHandling().accessDeniedPage("/403");
    }


    //Configuracoes de recursos estaticos(js, css, imagens, etc.)
    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/pages/login/login.jsf","/**.html", "/**.xhtml", "/**.jsf", "/webjars/**", "/resources/**",  "/javax.faces.resource/**");
    }

}

CustomAuthenticationProvider.class

package br.com.coletadedados.config.spring.autenticacao;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

import br.com.coletadedados.model.Usuario;
import br.com.coletadedados.repository.UsuarioRepository;

@Configuration("customAuthenticationProvider")
public class CustomAuthenticationProvider implements AuthenticationProvider{

    @Autowired
    private UsuarioRepository usuarioRepository;
//    @Autowired
//    private UsuarioService usuarioService;

    private PasswordEncoder passwordEncoder = new BCryptPasswordEncoder();

    @Override
    public Authentication authenticate(Authentication authentication)
            throws AuthenticationException {
        System.out.println("Entrou no CustomAuthenticationProvider");
        UsernamePasswordAuthenticationToken userToken = (UsernamePasswordAuthenticationToken) authentication;
        String loginFornecido = userToken.getName();
        String senhaFornecida = (String) userToken.getCredentials();

        verificarPreenchimentoLoginESenha(loginFornecido, senhaFornecida);
//        Usuario details = usuarioService.obterUsuario(loginFornecido);
        Usuario details = usuarioRepository.findByNickname(loginFornecido).orElse(null);
        verificarLoginESenha(senhaFornecida, details);

        return new UsernamePasswordAuthenticationToken(details, senhaFornecida, details.getAuthorities());
    }

    private void verificarLoginESenha(String senhaFornecida, Usuario details) {
        if (details == null) {
            throw new BadCredentialsException("Login e/ou senha inválidos");
        }

        if (!passwordEncoder.matches(senhaFornecida, details.getPassword())) {
            throw new BadCredentialsException("Login e/ou senha inválidos");
        }
    }

    private void verificarPreenchimentoLoginESenha(String loginFornecido, String senhaFornecida) {
        if (loginFornecido == null || loginFornecido.trim().equals("")
                || senhaFornecida == null
                || senhaFornecida.trim().equals(""))
            throw new BadCredentialsException(
                    "Os campos login e senha são obrigatórios");
    }

    @SuppressWarnings("rawtypes")
    @Override
    public boolean supports(Class authentication) {
        return (UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication));
    }

}

Alguém consegue me ajudar?