I did an implementation of Spring Boot with Security simple only for this, with access to User and Password via Html, database Postgres however, it can be any other sql.
With a table: user
With the fields: id
, username
, password
If you want you can create the table in postgres with the command:
CREATE TABLE user(
id serial PRIMARY KEY,
username VARCHAR (50) UNIQUE NOT NULL,
password VARCHAR (250) NOT NULL
);
But you can also let Hibernate generate for you by configuring the file: application.properties
with the following instruction:
spring.jpa.hibernate.ddl-auto=create
If you really want to create the table at hand, then change this statement to validate:
spring.jpa.hibernate.ddl-auto=validate
Implementation for Userdetailsservice:
package hello;
import java.util.Optional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
@Service(value = "usuarioService")
public class MyUserDetailService implements UserDetailsService {
@Autowired
private UsuarioRepo usuarioRepo;
@Autowired
private BCryptPasswordEncoder bcryptEncoder;
@Override
public UserDetails loadUserByUsername(String username) {
Optional<User> opt = usuarioRepo.findByUsername(username);
User user = null;
if(opt.isPresent()){
user = opt.get();
}
if (user == null) {
throw new UsernameNotFoundException(username);
}
return new MyUserPrincipal(user);
}
public User save(User usuario) {
usuario.setPassword(bcryptEncoder.encode(usuario.getPassword()));
return usuarioRepo.save(usuario);
}
}
Implementation of Userdetails:
package hello;
import java.util.Collection;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import lombok.Getter;
import lombok.Setter;
@Getter @Setter
public class MyUserPrincipal implements UserDetails {
private static final long serialVersionUID = -8489053074208206273L;
private User user;
public MyUserPrincipal(User user) {
this.user = user;
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return null;
}
@Override
public String getPassword() {
return user.getPassword();
}
@Override
public String getUsername() {
return user.getUsername();
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return true;
}
}
User Entity:
package hello;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@Getter @Setter @AllArgsConstructor @NoArgsConstructor
@Entity
public class User {
//FIXME: #### está funcionando, mas o ideal é depois avaliar o uso de Sequence, Identity, Serial...
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@Column(nullable = false, unique = true)
private String username;
private String password;
}
Repository:
package hello;
import java.util.Optional;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface UsuarioRepo extends CrudRepository<User, String> {
Optional<User> findByUsername(String username);
}
Implementation of Websecurityconfigureradapter:
package hello;
import javax.annotation.Resource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
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.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;
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
//FIXME: #### após os testes, remover o mapeamento new-user tanto da controller como das permissoes abaixo ####
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/", "/home", "/new-user").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.permitAll()
.and()
.logout()
.permitAll();
}
@Override
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Autowired
public void globalUserDetails(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(encoder());
}
@Bean
public BCryptPasswordEncoder encoder(){
return new BCryptPasswordEncoder();
}
@Resource(name = "usuarioService")
private UserDetailsService userDetailsService;
}
Controller:
package hello;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
//FIXME: #### quando tudo já estiver ok, e o usuário já criado, remover o mapeamento new-user ####
@Controller
public class UsuarioController {
@Autowired
MyUserDetailService usuarioService;
@GetMapping("/")
public String root() {
return "login";
}
@GetMapping("/login")
public String login() {
return "login";
}
@GetMapping("/hello")
public String hello() {
return "hello";
}
@GetMapping("/home")
public String home() {
return "home";
}
@GetMapping("/new-user")
public String newUser() {
User usuario = new User();
usuario.setId(1L);
usuario.setUsername("danilo");
usuario.setPassword("123");
usuarioService.save(usuario);
return usuario.toString();
}
}
Pom.xml
using postgres, jpa, Thymeleaf, and Lombok
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.springframework</groupId>
<artifactId>gs-securing-web</artifactId>
<version>0.1.0</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.6.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
<properties>
<java.version>1.8</java.version>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
application properties:
Configure the database, user and password
spring.datasource.hikari.connectionTimeout=100000
spring.datasource.hikari.maximumPoolSize=50
#escolha um banco de dados, nesse caso esta: dbteste
spring.datasource.url=jdbc:postgresql://localhost:5432/dbteste
spring.datasource.username=userteste
spring.datasource.password=senha
#create ira criar a tabela
#create-drop ao encerrar a aplicacao ele dropa as tabelas
#validate ele verifica se as tabelas estao conforme as entidades
spring.jpa.hibernate.ddl-auto=create #validate #create-drop
hello.html:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="https://www.thymeleaf.org"
xmlns:sec="https://www.thymeleaf.org/thymeleaf-extras-springsecurity3">
<head>
<title>Hello World!</title>
</head>
<body>
<h1 th:inline="text">Hello [[${#httpServletRequest.remoteUser}]]!</h1>
<form th:action="@{/logout}" method="post">
<input type="submit" value="Sign Out"/>
</form>
</body>
</html>
login.html:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="https://www.thymeleaf.org"
xmlns:sec="https://www.thymeleaf.org/thymeleaf-extras-springsecurity3">
<head>
<title>Spring Security Example </title>
</head>
<body>
<div th:if="${param.error}">
Invalid username and password.
</div>
<div th:if="${param.logout}">
You have been logged out.
</div>
<form th:action="@{/login}" method="post">
<div><label> User Name : <input type="text" name="username"/> </label></div>
<div><label> Password: <input type="password" name="password"/> </label></div>
<div><input type="submit" value="Sign In"/></div>
</form>
</body>
</html>
home html.:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="https://www.thymeleaf.org" xmlns:sec="https://www.thymeleaf.org/thymeleaf-extras-springsecurity3">
<head>
<title>Spring Security Example</title>
</head>
<body>
<h1>Welcome!</h1>
<p>Click <a th:href="@{/hello}">here</a> to see a greeting.</p>
</body>
</html>
pages were created (home html.,hello.html,login.html) using the Thymeleaf+spring boot convention:
Execute the command:
On linux:
mvn clean install; java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=8000 -jar target/Gs-Securing-web-0.1.0.jar
On Windows:
mvn clean install & java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=8000 -jar target/Gs-Securing-web-0.1.0.jar
Sign in:
http://localhost:8080/new-user
An error page will appear, as it will try to upload to a Thymeleaf template that does not exist, however, with the user created in the description:
Log in now to the page:
http://localhost:8080/hello
You will not be logged in and will be redirected, log in, and password: Anilo, 123
After logging in, you will be automatically redirected to the hello page:
you will not be able to even, because, the authentication is not searching from the database, review your file Securitywebconfig in the configure method, you are using: auth.inMemoryAuthentication(), and should use: userDetailsService in which it is commented
– danilo
the findByNomeuser method is strange, check if it is really working and how is the nomenclature in the Entity, would not be, findByNomeUsuario?
– danilo
This with auth.inMemoryAuthentication() because it was testing, but with what this commented also did not work. About findByNomeUsuario, I did the same as this in the User model as this user name
– Lucas Carravetta
change findByNomeuser to findByNomeUsuario
– danilo
in the database the password must be encrypted, because you are using Bcryptpasswordencoder in Spring
– danilo
findByNomeUsuario so of the error. I will change in the bank and the model to see if this is it
– Lucas Carravetta
Yes, the bank is encrypted
– Lucas Carravetta
post in question your Entity and how is in the bank
– danilo
I posted on the question
– Lucas Carravetta
This example is complete, in your absence the Customauthenticationmanager, however, it uses JWT: https://answall.com/questions/149735/authenticates%C3%A7%C3%a3o-com-spring-security? Rq=1
– danilo
In my
ImplementsUserDetailsService
, i have these settings: @Resource(name = "userService") private Userdetailsservice userDetailsService; @Autowired public void globalUserDetails(Authenticationmanagerbuilder auth) throws Exception { auth.userDetailsService(userDetailsService). passwordEncoder(Encoder()); }– danilo
your
ImplementsUserDetailsService
is wrong, you need to write it down with@Service(value = "usuarioService")
instead of@Repository
– danilo
I altered it to identify the parameters by the hairs I created:
.formLogin().usernameParameter("nomeUsuario").passwordParameter("senha").loginPage("/login") .permitAll()
but did not give tb, I will try to make these other changes you sent– Lucas Carravetta
What is the version of your spring? spring mvc 4? mvc 3? is spring boot?
– danilo
Spring boot 2.1.6
– Lucas Carravetta
updated my answer, I am using Spring Boot 2.0.1
– danilo