Prerequisites
I am using
- vscode for IDE.
- Ubuntu18 for OS
- Java 1.8
Preparations
Go to start.spring.io and download a project.
My configuration is the following:
Artifact ID: login-demo
Dependencies:
Artifact ID: login-demo
Dependencies:
- Web,
- Security (for login functionality),
- Thymeleaf (for view),
- JPA (for database access)
- MySQL (database driver)
To add these dependencies, search for dependency in the "Search for dependencies" and click the suggestion. After configuring everything, click on "Generate Project". The downloaded zip will be used after creating a database.
Create a database
Install mariadb and create a database to store user information. (You can use mysql57 too if you prefer mysql.)
If you are Ubuntu user like me, you can see here for how to install mariadb-server. If you are a Windows user, get an installer from here.
If you are Ubuntu user like me, you can see here for how to install mariadb-server. If you are a Windows user, get an installer from here.
Once you start mariadb, create a dabase and a user table like this:
create database logindemo;
use logindemo;
CREATE TABLE users (
`id` bigint(20) unsigned NOT NULL UNIQUE AUTO_INCREMENT,
`name` VARCHAR(20) NOT NULL UNIQUE,
`password` CHAR(128)
);
INSERT INTO users (name, password)
VALUES ('test', '$2a$10$Fonnn4/zL3wGBvcyYbhIu.bz6q8CKuSyCQyIYqrpNdeVfO1J.Gn0S');
Start the project
Extract the downloaded zip from start.spring.io and open the unziped project by vscode. You can see here for how to open with vscode.
After opening the project, you will find application.properties here:
/login-demo/src/main/resources/application.properties
/login-demo/src/main/resources/application.properties
Write as follows inside:
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/logindemo
#your username of mariadb
spring.datasource.username=root
#your password of mariadb
spring.datasource.password=root
spring.jpa.show-sql=true
spring.messages.basename=messages
Then press F5 on your keyboard. If the app starts without error, it is success.
If it started without error, press
Shift + F5
and stop the app.Hello World page behind a login prompt
Create
controller/HelloWorldController.java
in logindemo directory.
Write as follows in the controller and save it:
package com.example.logindemo.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
@Controller
public class HelloWorldController {
@GetMapping(value = "/")
public String index(Model model) {
return "pages/index";
}
}
Create
pages/index.html
in login-demo/src/main/resources/templates
like this:
And write as follows in the index.html and save it:
<h1>Hello World</h1>
Now start the app again by pressing F5. And look at http://localhost:8080.
You will be asked to login:
Of course you can not login yet whatever you write.
Once you confirmed that it is working, stop the app by pressing
Once you confirmed that it is working, stop the app by pressing
Shift+F5
.User Model
At first, we need to make a model file of User table. Create
User.java
in login-demo/src/main/java/com/example/logindemo/model
.
Then write as follows in the User.java:
package com.example.logindemo.model;
import javax.persistence.Entity;
import javax.persistence.Table;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
@Entity
@Table(name = "users")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
private String name;
private String password;
public long getId() {
return this.id;
}
public void setId(long id) {
this.id = id;
}
public String getName() {
return this.name;
}
public String getUsername() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return this.password;
}
public void setPassword(String password) {
this.password = password;
}
}
Also we need to make UserRepository to access the database. Create
repository/UserRepository.java
:
And write as follows inside:
package com.example.logindemo.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import org.springframework.data.jpa.repository.Query;
import com.example.logindemo.model.User;
@Repository
public interface UserRepository extends JpaRepository<User,Long>{
@Query("select u from User u where u.name = :name")
User findByName(String name);
}
UserDetailsService
We need a UserDetailsService. Create
service/UserDetailsServiceImpl.java
.
and write as follows:
package com.example.logindemo.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
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 java.util.HashSet;
import java.util.Set;
import com.example.logindemo.repository.UserRepository;
import com.example.logindemo.model.User;
@Service
public class UserDetailsServiceImpl implements UserDetailsService{
@Autowired
private UserRepository userRepository;
@Override
@Transactional(readOnly = true)
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userRepository.findByName(username);
if(user == null){
throw new UsernameNotFoundException("This user name \""+ username +"\" was not found in our database.");
}
Set<GrantedAuthority> grantedAuthorities = new HashSet<>();
//grantedAuthorities.add(new SimpleGrantedAuthority(user.getRole().getName()));
return new org.springframework.security.core.userdetails.User(user.getName(), user.getPassword(), grantedAuthorities);
}
}
Security Config
You can configure the login functionality from this file. If you want to use customized login page, uncomment
Write as follows inside the
.loginPage("/login")
and create a login.html in templates
folder.Write as follows inside the
SecurityConfig.java
:package com.example.logindemo.config;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private UserDetailsService userDetailsService;
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests()
//.antMatchers("/create_user", "/about", "/non_login/**").permitAll()
//.antMatchers("/admin/**").hasAnyRole("ADMIN")
//.antMatchers("/user/**").hasAnyRole("USER")
.anyRequest().authenticated()
.and()
.formLogin()
// .loginPage("/login")
.permitAll()
.and()
.logout()
.permitAll();
//.logoutRequestMatcher(new AntPathRequestMatcher("/login?logout"));
}
@Bean
public BCryptPasswordEncoder bCryptPasswordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
public AuthenticationManager customAuthenticationManager() throws Exception {
return authenticationManager();
}
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder());
}
}
Check if it works
After pressing F5 and starting the app on the vscode, go to http://localhost:8080/login and fill the necessary information and submit.
The user name: test
The password: 12345678
The user name: test
The password: 12345678
You can login and see the hello world behind the login prompt now: