Building a blogging website with microservices: sign up
Hi. This is the thirteenth part of the diary about developing the “Programmers’ diary” blog. The open source code of this project is on https://github.com/TheProgrammersDiary. The twelfth part: https://hashnode.programmersdiary.com/building-a-blogging-website-with-microservices-log-aggregation-and-monitoring.
The first diary entry contains explanation on why this project was done: https://medium.com/@vievaldas/developing-a-website-with-microservices-part-1-the-idea-fe6e0a7a96b5.
Next entry:
—————
2023-11-02:
Let’s do user sign up.
I will employ the fancy design I have taken from https://larainfo.com/blogs/nextjs-with-tailwind-login-page-example to facilitate implementation of user sign up in blog microservice.
Note that here I will only paste code which I think needs the most explanation. For all changes in BE check commit: https://github.com/TheProgrammersDiary/Blog/commit/78544d054a60c58b81af05d2b68cb76d0b217a20.
Let’s start from dependencies. I want to use relational db for this, so let’s import postgres, liquibase and data jpa. Spring security is needed for password encryption (we don’t want to keep plain passwords in the database), Spring validation import is needed for backend (BE) email validation.
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
</dependency>
<dependency>
<groupId>org.liquibase</groupId>
<artifactId>liquibase-core</artifactId>
<version>4.23.1</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
<version>RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
We need a db to store user data. Post microservice already has a database but since we are following microservice architecture, we need a new database for blog microservice. Here the database container is defined in docker folder docker-compose.yaml:
postgres_blog:
image: postgres:15.4
container_name: postgres_blog
ports:
- "5433:5432"
environment:
POSTGRES_USER: blog
POSTGRES_PASSWORD: admin
POSTGRES_DB: users
Let’s prepare Liquibase so we could change our database structure while keeping the database running:
liquibase/postgres/changelog/liquibase.changelog_master.yaml:
databaseChangeLog:
- include:
file: classpath:/liquibase/postgresql/changelog/001_user.sql
Then, near MongoDB config, we need to add postgres and liquibase configs (in application-docker.yaml):
spring:
data:
mongodb:
uri: mongodb://mongodb:27017
database: blog
datasource:
url: jdbc:postgresql://postgres_blog:5432/users
username: blog
password: admin
driver-class-name: org.postgresql.Driver
jpa:
properties:
hibernate:
dialect: org.hibernate.dialect.PostgreSQLDialect
liquibase:
change-log: classpath:/liquibase/postgresql/changelog/liquibase.changelog_master.yaml
The postgres db container we use is called postgres_blog (posts microservice has its own db called postgres). The database which is inside the postgres_db container is named users. That’s why the datasource url is jdbc:postgresql://postgres_blog:5432/users.
Let’s add the first table containing user login data:
liquibase/postgres/changelog/001_user.sql:
CREATE TABLE IF NOT EXISTS blog_user (
id VARCHAR(255) PRIMARY KEY,
username VARCHAR(255) NOT NULL,
email VARCHAR(255) NOT NULL,
password VARCHAR(255) NOT NULL
);
user is a reserved keyword in postgres so blog_user is used as a table name.
In UserRepository we can validate email address in BE and pop the error message:
@Column(nullable = false, unique = true)
@Email(message = "Invalid email address")
private String email;
Since we want to protect passwords (not to store them as plain text), we need to add password encoder. Also, since we use Spring security, for now, we need to add a configuration to allow all requests (since we not yet implemented the login functionality).
@Configuration
public class SecurityConfig {
@Bean
public static PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http.csrf(csrf -> csrf.disable()).authorizeHttpRequests(requests -> requests.anyRequest().permitAll());
return http.build();
}
}
So we add this password encoder and then can use it to encode the password of user before saving it to db.
For FE changes check this commit: https://github.com/TheProgrammersDiary/Frontend/commit/b534afad5c86847c480e14d56a52de4b007a55e4.
I have created few accounts and got this in db:
There is no duplicate user validation, yet the basic functionality is working.
For all six entries I entered the password: abc. Notice that the password entries are different. That’s the behaviour of a strong password encryption. If you have an attacker, you don’t want the same input to have the same output, since if attacker steals the db data, he can check which encrypted password combination occurs most frequently and guess the most common passwords for victim users who use these most common passwords. Since the same input generates different output, this trick is harder to do. I have learned this from Serious Cryptography A Practical Introduction to Modern Encryption from Jean-Philippe Aumasson (one of the creators of Blake 2 algorithm which competed with SHA3), truly amazing book if you are really interested in how encryption works.
OK, so basic stuff is working, time to rest.
—————
Thanks for reading.
The project logged in this diary is open source, so if you would like to code or suggest changes, please visit https://github.com/TheProgrammersDiary.
You can check out the website: https://www.programmersdiary.com/.
Next part coming soon.
Subscribe to my newsletter
Read articles from Evaldas Visockas directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by