Spring dan MongoDB USER LOGIN
Jika sebelumnya kita membuat artikel Spring Boot MongoDB - Simple App Tutorial, sekarang kita bangun USER LOGIN dari nol, berangkat dari collection users di MongoDB dan Spring Boot, rapi, aman, dan clean-code minded.
TARGET AKHIR
-
Collection:
users -
Fitur:
-
Register user
-
Login user
-
Password di-hash (BCrypt)
-
-
Tanpa Spring Security dulu (biar alur logika login mudah dipahami)
STEP 1 — Struktur Collection users (MongoDB)
Di MongoDB, user kita akan berbentuk seperti ini:
"_id": ObjectId("..."),
"name": "Yusuf",
"email": "yusuf@gmail.com",
"passwordHash": "$2a$10$..."
}
Prinsip penting:
-
Tidak ada password plain
-
Tidak ada token di DB
-
Email unique
-
Password = hash
STEP 2 — User Entity (Domain Layer)
domain/User.java
Gunakan record supaya ringkas & immutable.
package com.yusuf.springmongoclean.domain;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
@Document(collection = "users")
public record User(
@Id String id,
String name,
String email,
String passwordHash
) {}
Kenapa ini clean:
-
Tidak ada setter
-
Data tidak bisa “diubah diam-diam”
-
Cocok untuk auth data
STEP 3 — User Repository
repository/UserRepository.java
package com.yusuf.springmongoclean.repository;
import com.yusuf.springmongoclean.domain.User;
import org.springframework.data.mongodb.repository.MongoRepository;
import java.util.Optional;
public interface UserRepository extends MongoRepository<User, String> {
Optional<User> findByEmail(String email);
}
findByEmail = jantung login.
STEP 4 — DTO (Request Object)
Register Request
package com.yusuf.springmongoclean.dto.security;
public record RegisterRequest(
String name,
String email,
String password
) {}
Login Request
package com.yusuf.springmongoclean.dto.security;
public record LoginRequest(
String email,
String password
) {}
STEP 5 — Password Encoder (BCrypt)
Tambahkan dependency (jika belum):
implementation 'org.springframework.security:spring-security-crypto'Ini bukan full Spring Security, cuma util crypto.
STEP 6 — Auth Service (INTI LOGIN)
service/AuthService.java
package com.yusuf.springmongoclean.service;
import com.yusuf.springmongoclean.domain.User;
import com.yusuf.springmongoclean.repository.UserRepository;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
@Service
public class AuthService {
private final UserRepository repository;
private final BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
public AuthService(UserRepository repository) {
this.repository = repository;
}
// REGISTER
public User register(String name, String email, String password) {
repository.findByEmail(email)
.ifPresent(user -> {
throw new IllegalArgumentException("Email already registered");
});
String passwordHash = encoder.encode(password);
return repository.save(
new User(null, name, email, passwordHash)
);
}
// LOGIN
public User login(String email, String password) {
User user = repository.findByEmail(email)
.orElseThrow(() ->
new IllegalArgumentException("Invalid email or password")
);
if (!encoder.matches(password, user.passwordHash())) {
throw new IllegalArgumentException("Invalid email or password");
}
return user;
}
}
Kenapa error message sama?
-> Supaya attacker tidak tahu email mana yang valid.
STEP 7 — Auth Controller
controller/AuthController.java
package com.yusuf.springmongoclean.service;
import com.yusuf.springmongoclean.domain.User;
import com.yusuf.springmongoclean.repository.UserRepository;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
@Service
public class AuthService {
private final UserRepository repository;
private final BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
public AuthService(UserRepository repository) {
this.repository = repository;
}
// REGISTER
public User register(String name, String email, String password) {
repository.findByEmail(email)
.ifPresent(user -> {
throw new IllegalArgumentException("Email already registered");
});
String passwordHash = encoder.encode(password);
return repository.save(
new User(null, name, email, passwordHash)
);
}
// LOGIN
public User login(String email, String password) {
User user = repository.findByEmail(email)
.orElseThrow(() ->
new IllegalArgumentException("Invalid email or password")
);
if (!encoder.matches(password, user.passwordHash())) {
throw new IllegalArgumentException("Invalid email or password");
}
return user;
}
}
STEP 8 — Test API
Register
postman request POST 'http://localhost:8080/auth/register' \ --header 'Content-Type: application/json' \ --body '{ "name": "Bunny", "email": "Bunny@gmail.com", "password": "secret123"}'
Login
postman request POST 'http://localhost:8080/auth/login' \ --header 'Content-Type: application/json' \ --body '{ "email": "Bunny@gmail.com", "password": "secret1231"}'
Comments
Post a Comment