My Custom UserDetailsService
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import br.com.fimd.entidades.Usuario;
import br.com.fimd.service.UsuarioService;
@Transactional(readOnly=true)
@Service("userDetailsServiceImpl")
public class UserDetailsServiceImpl implements UserDetailsService{
@Autowired
private UsuarioService usuarioService;
@Override
public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException {
Usuario usuario = usuarioService.findUserByEmail(email);
if(usuario == null) {
throw new UsernameNotFoundException("Usuário nao encontrado.");
}
return new User(usuario.getEmail(), usuario.getSenha(), usuario.getAuthorities());
}
}
My Security Configuration
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
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.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Autowired
@Qualifier("userDetailsServiceImpl")
private UserDetailsService userDetailsService;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(new BCryptPasswordEncoder());
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().disable().
csrf().disable().authorizeRequests()
.antMatchers("/home").permitAll()
.antMatchers("/public/**").permitAll()
.antMatchers("/private/**").hasRole("USER")
//.antMatchers("/admin*").access("hasRole('ROLE_ADMIN')")
.antMatchers("/admin/**").hasRole("ADMIN")
.anyRequest().authenticated()
.and()
//.addFilterBefore(new JWTAuthenticationFilter(),UsernamePasswordAuthenticationFilter.class)
.logout().logoutRequestMatcher(new AntPathRequestMatcher("/logout"));
}
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/assets/**");
}
@Bean
CorsConfigurationSource corsConfigurationSource() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", new CorsConfiguration().applyPermitDefaultValues());
return source;
}
}
My User Entity
import java.io.Serializable;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EntityListeners;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.validation.constraints.NotBlank;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
@Entity
@Table(name = "usuarios")
@EntityListeners(AuditingEntityListener.class)
@JsonIgnoreProperties(value = { "createdAt", "updatedAt" }, allowGetters = true)
public class Usuario implements UserDetails, Serializable{
private static final long serialVersionUID = 4038437690572999966L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "user_id")
private Long id;
@NotBlank
private String nome;
@NotBlank
private String email;
@NotBlank
private String senha;
@NotBlank
private String cpf;
@Column
private boolean ativo;
@ManyToMany
@JoinTable(name="perfil_usuario", joinColumns=
{@JoinColumn(name="user_id")}, inverseJoinColumns=
{@JoinColumn(name="tipo_perfil")})
private Set<Perfil> perfis = new HashSet<>();
@OneToMany(mappedBy = "usuario", cascade = CascadeType.ALL)
private List<Investimento> investimentos;
@OneToMany(mappedBy = "usuario", cascade = CascadeType.ALL)
private List<Extrato> extratos;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getNome() {
return nome;
}
public void setNome(String nome) {
this.nome = nome;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getCpf() {
return cpf;
}
public void setCpf(String cpf) {
this.cpf = cpf;
}
public static long getSerialversionuid() {
return serialVersionUID;
}
public String getSenha() {
return senha;
}
public void setSenha(String senha) {
this.senha = senha;
}
public boolean isAtivo() {
return ativo;
}
public void setAtivo(boolean ativo) {
this.ativo = ativo;
}
public Set<Perfil> getPerfis() {
return perfis;
}
public void setPerfis(Set<Perfil> perfis) {
this.perfis = perfis;
}
public List<Investimento> getInvestimentos() {
return investimentos;
}
public void setInvestimentos(List<Investimento> investimentos) {
this.investimentos = investimentos;
}
public List<Extrato> getExtratos() {
return extratos;
}
public void setExtratos(List<Extrato> extratos) {
this.extratos = extratos;
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return this.perfis;
}
@Override
public String getPassword() {
return this.senha;
}
@Override
public String getUsername() {
return this.email;
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return true;
}
}
My Perfil Entity
import java.util.List;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.ManyToMany;
import org.springframework.security.core.GrantedAuthority;
@Entity
public class Perfil implements GrantedAuthority{
private static final long serialVersionUID = 1L;
@Id
private String tipoPerfil;
@ManyToMany(mappedBy="perfis")
private List<Usuario> usuarios;
public List<Usuario> getUsuarios() {
return usuarios;
}
public void setUsuarios(List<Usuario> usuarios) {
this.usuarios = usuarios;
}
public String getTipoPerfil() {
return tipoPerfil;
}
public void setTipoPerfil(String tipoPerfil) {
this.tipoPerfil = tipoPerfil;
}
@Override
public String getAuthority() {
return this.tipoPerfil;
}
}
My Spring Filter Initializer
import org.springframework.context.annotation.Configuration;
import org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer;
@Configuration
public class SecurityInitializer extends AbstractSecurityWebApplicationInitializer {
}
When i call a "/private/service" my loadUserByUsername not being called never, my application ever send me a 403 forbidden, access denied. Why that? I tried a lot of tutorials from internet and my code seems to be correct, i'm using spring starter 2.0.5.RELEASE
I already tried to call the userDetailsService from a @Bean method in SecurityConfiguration
Your security configuration is not complete, you must provide as well the login information:
.formLogin()
.loginPage("/login.html")
.defaultSuccessUrl("/home")
.failureUrl("/login.html?error=true")
Otherwise all your requests will be unauthorized. Please see this tutorial:
Your Custom UserDetails service will be called only when the application will receive a POST to login url with username and password, otherwise it will not have what data to authorize.