Refactor to use SpringJPA
This commit is contained in:
parent
7ebd6a2587
commit
ed30a5f712
@ -26,6 +26,8 @@ repositories {
|
|||||||
dependencies {
|
dependencies {
|
||||||
implementation 'org.springframework.boot:spring-boot-starter-security'
|
implementation 'org.springframework.boot:spring-boot-starter-security'
|
||||||
implementation 'org.springframework.boot:spring-boot-starter-web'
|
implementation 'org.springframework.boot:spring-boot-starter-web'
|
||||||
|
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
|
||||||
|
runtimeOnly 'org.postgresql:postgresql'
|
||||||
compileOnly 'org.projectlombok:lombok'
|
compileOnly 'org.projectlombok:lombok'
|
||||||
developmentOnly 'org.springframework.boot:spring-boot-devtools'
|
developmentOnly 'org.springframework.boot:spring-boot-devtools'
|
||||||
annotationProcessor 'org.projectlombok:lombok'
|
annotationProcessor 'org.projectlombok:lombok'
|
||||||
|
21
db/docker-compose.yml
Normal file
21
db/docker-compose.yml
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
version: '3.8'
|
||||||
|
services:
|
||||||
|
cc-database:
|
||||||
|
image: postgres
|
||||||
|
restart: always
|
||||||
|
environment:
|
||||||
|
POSTGRES_USER: biblenotes
|
||||||
|
POSTGRES_PASSWORD: ujhfdogiuhfdgiusdfhoviufdnpviusdhdfiuqbfoiudzsfzidfugofduszbdv
|
||||||
|
POSTGRES_DB: biblenotes
|
||||||
|
volumes:
|
||||||
|
- ./sql-scripts:/docker-entrypoint-initdb.d
|
||||||
|
ports:
|
||||||
|
- "5432:5432"
|
||||||
|
|
||||||
|
adminer:
|
||||||
|
image: adminer
|
||||||
|
restart: always
|
||||||
|
environment:
|
||||||
|
ADMINER_DEFAULT_SERVER: biblenotes
|
||||||
|
ports:
|
||||||
|
- "8081:8081"
|
19
db/sql-scripts/init.sql
Normal file
19
db/sql-scripts/init.sql
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
CREATE TABLE users
|
||||||
|
(
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
username VARCHAR(255) UNIQUE NOT NULL,
|
||||||
|
password VARCHAR(255) NOT NULL,
|
||||||
|
email VARCHAR(255) UNIQUE NOT NULL,
|
||||||
|
role VARCHAR(255) NOT NULL,
|
||||||
|
created_at TIMESTAMP NOT NULL,
|
||||||
|
updated_at TIMESTAMP NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE user_logins
|
||||||
|
(
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
user_id BIGINT NOT NULL,
|
||||||
|
login_time TIMESTAMP NOT NULL,
|
||||||
|
login_ip VARCHAR(255) NOT NULL,
|
||||||
|
FOREIGN KEY (user_id) REFERENCES users (id)
|
||||||
|
);
|
45
src/main/java/de/w665/biblenotes/db/DatabaseInitService.java
Normal file
45
src/main/java/de/w665/biblenotes/db/DatabaseInitService.java
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
package de.w665.biblenotes.db;
|
||||||
|
|
||||||
|
import de.w665.biblenotes.db.entity.Role;
|
||||||
|
import de.w665.biblenotes.db.entity.User;
|
||||||
|
import de.w665.biblenotes.db.repo.UserRepository;
|
||||||
|
import jakarta.annotation.PostConstruct;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
@Slf4j
|
||||||
|
public class DatabaseInitService {
|
||||||
|
|
||||||
|
@Value("${database.init.create-default-admin-user}")
|
||||||
|
private boolean createAdminUser;
|
||||||
|
|
||||||
|
private final UserRepository userRepository;
|
||||||
|
|
||||||
|
public DatabaseInitService(UserRepository userRepository) {
|
||||||
|
this.userRepository = userRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostConstruct
|
||||||
|
public void init() {
|
||||||
|
if(createAdminUser && userRepository.count() == 0) {
|
||||||
|
createDefaultAdminUser();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createDefaultAdminUser() {
|
||||||
|
log.debug("Inserting admin user...");
|
||||||
|
User user = new User();
|
||||||
|
user.setUsername("admin");
|
||||||
|
user.setPassword("$2a$10$y5u4UL6JwacDrMzXEJqqQO.1Cf3xoZTRhUTab4We/zxnWneI5jTf2");
|
||||||
|
user.setEmail("admin@example.com");
|
||||||
|
user.setRole(Role.ADMINISTRATOR);
|
||||||
|
user.setCreatedAt(LocalDateTime.now());
|
||||||
|
user.setUpdatedAt(LocalDateTime.now());
|
||||||
|
userRepository.save(user);
|
||||||
|
log.debug("Admin user insertion done.");
|
||||||
|
}
|
||||||
|
}
|
@ -1,18 +0,0 @@
|
|||||||
package de.w665.biblenotes.db;
|
|
||||||
|
|
||||||
import lombok.Getter;
|
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
|
||||||
import org.springframework.context.annotation.Configuration;
|
|
||||||
|
|
||||||
@Getter
|
|
||||||
@Configuration
|
|
||||||
public class RethinkDBConfig {
|
|
||||||
@Value("${rethinkdb.host}")
|
|
||||||
private String host;
|
|
||||||
|
|
||||||
@Value("${rethinkdb.port}")
|
|
||||||
private int port;
|
|
||||||
|
|
||||||
@Value("${rethinkdb.database}")
|
|
||||||
private String database;
|
|
||||||
}
|
|
@ -1,27 +0,0 @@
|
|||||||
package de.w665.biblenotes.db;
|
|
||||||
|
|
||||||
import com.rethinkdb.RethinkDB;
|
|
||||||
import com.rethinkdb.net.Connection;
|
|
||||||
import jakarta.annotation.PostConstruct;
|
|
||||||
import lombok.Getter;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
|
|
||||||
@Slf4j
|
|
||||||
@Component
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
public class RethinkDBConnector {
|
|
||||||
|
|
||||||
private final RethinkDBConfig config;
|
|
||||||
@Getter
|
|
||||||
private final RethinkDB r = RethinkDB.r;
|
|
||||||
@Getter
|
|
||||||
private Connection connection;
|
|
||||||
|
|
||||||
@PostConstruct
|
|
||||||
public void connectToDatabae() {
|
|
||||||
connection = r.connection().hostname(config.getHost()).port(config.getPort()).connect();
|
|
||||||
log.info("Connected to RethinkDB at " + config.getHost() + ":" + config.getPort() + " on database " + config.getDatabase());
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,123 +0,0 @@
|
|||||||
package de.w665.biblenotes.db;
|
|
||||||
|
|
||||||
import com.rethinkdb.RethinkDB;
|
|
||||||
import com.rethinkdb.gen.exc.ReqlOpFailedError;
|
|
||||||
import com.rethinkdb.net.Connection;
|
|
||||||
import de.w665.biblenotes.db.repo.UserRepository;
|
|
||||||
import de.w665.biblenotes.model.User;
|
|
||||||
import jakarta.annotation.PostConstruct;
|
|
||||||
import jakarta.annotation.PreDestroy;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
|
||||||
import org.springframework.cglib.core.Local;
|
|
||||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
|
|
||||||
import java.time.LocalDateTime;
|
|
||||||
import java.time.ZonedDateTime;
|
|
||||||
import java.time.format.DateTimeFormatter;
|
|
||||||
import java.util.Date;
|
|
||||||
import java.util.Optional;
|
|
||||||
|
|
||||||
@Slf4j
|
|
||||||
@Service
|
|
||||||
public class RethinkDBService {
|
|
||||||
|
|
||||||
private final RethinkDBConfig config;
|
|
||||||
private final RethinkDB r;
|
|
||||||
private final Connection connection;
|
|
||||||
private final UserRepository userRepository;
|
|
||||||
|
|
||||||
@Value("${biblenotes.auto-reset-on-startup}")
|
|
||||||
private boolean autoResetOnStartup;
|
|
||||||
@Value("${biblenotes.management.user.username}")
|
|
||||||
private String defaultUsername;
|
|
||||||
@Value("${biblenotes.management.user.password}")
|
|
||||||
private String defaultPassword;
|
|
||||||
|
|
||||||
private final BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
public RethinkDBService(RethinkDBConfig config, RethinkDBConnector connector, UserRepository userRepository) {
|
|
||||||
this.config = config;
|
|
||||||
|
|
||||||
// mapping to private vars for easier access
|
|
||||||
this.r = connector.getR();
|
|
||||||
this.connection = connector.getConnection();
|
|
||||||
this.userRepository = userRepository;
|
|
||||||
}
|
|
||||||
|
|
||||||
@PostConstruct
|
|
||||||
public void initialize() {
|
|
||||||
|
|
||||||
// rethinkdb check if database exists
|
|
||||||
try {
|
|
||||||
r.dbCreate(config.getDatabase()).run(connection).stream();
|
|
||||||
log.debug("Database " + config.getDatabase() + " created");
|
|
||||||
} catch (ReqlOpFailedError e) {
|
|
||||||
log.debug("Database " + config.getDatabase() + " already exists. Error: " + e.getClass().getSimpleName());
|
|
||||||
}
|
|
||||||
|
|
||||||
// rethinkdb check if table users exists
|
|
||||||
try {
|
|
||||||
r.db(config.getDatabase()).tableCreate("users").run(connection).stream();
|
|
||||||
log.debug("Table 'users' created successfully.");
|
|
||||||
} catch (ReqlOpFailedError e) {
|
|
||||||
log.debug("Table 'users' already exists.");
|
|
||||||
if(autoResetOnStartup) {
|
|
||||||
log.debug("Clearing content...");
|
|
||||||
r.db(config.getDatabase()).table("users").delete().run(connection);
|
|
||||||
log.debug("Table 'users' cleared successfully.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// rethinkdb check if table user_logins exists
|
|
||||||
try {
|
|
||||||
r.db(config.getDatabase()).tableCreate("user_logins").run(connection).stream();
|
|
||||||
log.debug("Table 'user_logins' created successfully.");
|
|
||||||
} catch (ReqlOpFailedError e) {
|
|
||||||
log.debug("Table 'user_logins' already exists.");
|
|
||||||
if(autoResetOnStartup) {
|
|
||||||
log.debug("Clearing content...");
|
|
||||||
r.db(config.getDatabase()).table("user_logins").delete().run(connection);
|
|
||||||
log.debug("Table 'user_logins' cleared successfully.");
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
try {
|
|
||||||
r.db(config.getDatabase()).table("user_logins").indexCreate("loginTime").run(connection);
|
|
||||||
log.debug("Secondary index 'loginTime' on table 'user_logins' successfully created.");
|
|
||||||
} catch (ReqlOpFailedError e) {
|
|
||||||
log.debug("Secondary index 'loginTime' already exists.");
|
|
||||||
} finally {
|
|
||||||
r.db(config.getDatabase()).table("user_logins").indexWait("loginTime").run(connection);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
initializeAdminUser();
|
|
||||||
|
|
||||||
log.info("Database ready for operation!");
|
|
||||||
}
|
|
||||||
|
|
||||||
private void initializeAdminUser() {
|
|
||||||
Optional<User> adminUser = userRepository.retrieveUserByUsername("admin");
|
|
||||||
if(adminUser.isEmpty()) {
|
|
||||||
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd-MM-yyyy'T'HH:mm:ss.SSSXXX");
|
|
||||||
ZonedDateTime now = ZonedDateTime.now();
|
|
||||||
|
|
||||||
User user = new User();
|
|
||||||
user.setUsername(defaultUsername);
|
|
||||||
user.setPassword(passwordEncoder.encode(defaultPassword));
|
|
||||||
user.setRole("ADMIN");
|
|
||||||
userRepository.insertUser(user);
|
|
||||||
log.debug("Admin user created with default credentials. Username: admin, Password: admin");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@PreDestroy
|
|
||||||
public void close() {
|
|
||||||
if (connection != null) {
|
|
||||||
connection.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
6
src/main/java/de/w665/biblenotes/db/entity/Role.java
Normal file
6
src/main/java/de/w665/biblenotes/db/entity/Role.java
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
package de.w665.biblenotes.db.entity;
|
||||||
|
|
||||||
|
public enum Role {
|
||||||
|
ADMINISTRATOR,
|
||||||
|
USER
|
||||||
|
}
|
37
src/main/java/de/w665/biblenotes/db/entity/User.java
Normal file
37
src/main/java/de/w665/biblenotes/db/entity/User.java
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
package de.w665.biblenotes.db.entity;
|
||||||
|
|
||||||
|
import jakarta.persistence.*;
|
||||||
|
import lombok.*;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Table(name = "users")
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
@ToString
|
||||||
|
public class User {
|
||||||
|
@Id
|
||||||
|
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
@Column(nullable = false, unique = true)
|
||||||
|
private String username;
|
||||||
|
|
||||||
|
@Column(nullable = false)
|
||||||
|
private String password;
|
||||||
|
|
||||||
|
@Column(nullable = false, unique = true)
|
||||||
|
private String email;
|
||||||
|
|
||||||
|
@Enumerated(EnumType.STRING)
|
||||||
|
@Column(nullable = false)
|
||||||
|
private Role role;
|
||||||
|
|
||||||
|
@Column(nullable = false)
|
||||||
|
private LocalDateTime createdAt;
|
||||||
|
|
||||||
|
@Column(nullable = false)
|
||||||
|
private LocalDateTime updatedAt;
|
||||||
|
}
|
28
src/main/java/de/w665/biblenotes/db/entity/UserLogin.java
Normal file
28
src/main/java/de/w665/biblenotes/db/entity/UserLogin.java
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
package de.w665.biblenotes.db.entity;
|
||||||
|
|
||||||
|
import jakarta.persistence.*;
|
||||||
|
import lombok.*;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Table(name = "user_logins")
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class UserLogin {
|
||||||
|
@Id
|
||||||
|
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
@Column(nullable = false)
|
||||||
|
private Long userId;
|
||||||
|
|
||||||
|
@Column(nullable = false)
|
||||||
|
private LocalDateTime loginTime;
|
||||||
|
|
||||||
|
@Column(nullable = false)
|
||||||
|
private String loginIp;
|
||||||
|
}
|
@ -1,67 +1,10 @@
|
|||||||
package de.w665.biblenotes.db.repo;
|
package de.w665.biblenotes.db.repo;
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import de.w665.biblenotes.db.entity.UserLogin;
|
||||||
import com.google.gson.Gson;
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
import com.rethinkdb.RethinkDB;
|
|
||||||
import com.rethinkdb.net.Connection;
|
|
||||||
import com.rethinkdb.net.Result;
|
|
||||||
import de.w665.biblenotes.db.RethinkDBConfig;
|
|
||||||
import de.w665.biblenotes.db.RethinkDBConnector;
|
|
||||||
import de.w665.biblenotes.model.UserLogin;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.stereotype.Repository;
|
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@Slf4j
|
public interface UserLoginRepository extends JpaRepository<UserLogin, Long> {
|
||||||
@Repository
|
List<UserLogin> findByUserIdOrderByLoginTimeDesc(Long userId);
|
||||||
public class UserLoginRepository {
|
|
||||||
private final RethinkDB r;
|
|
||||||
private final Connection connection;
|
|
||||||
private final RethinkDBConfig config;
|
|
||||||
private final String TABLE_NAME = "user_logins";
|
|
||||||
|
|
||||||
private final Gson gson = new Gson();
|
|
||||||
private final ObjectMapper mapper = new ObjectMapper();
|
|
||||||
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
public UserLoginRepository(RethinkDBConnector connector, RethinkDBConfig config) {
|
|
||||||
this.r = connector.getR();
|
|
||||||
this.connection = connector.getConnection();
|
|
||||||
this.config = config;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void insertUserLogin(UserLogin userLogin) {
|
|
||||||
String uuid = r.uuid().run(connection, String.class).first();
|
|
||||||
userLogin.setId(uuid);
|
|
||||||
r.db(config.getDatabase()).table(TABLE_NAME).insert(userLogin).run(connection);
|
|
||||||
}
|
|
||||||
|
|
||||||
public UserLogin getLastLogin(String userId) {
|
|
||||||
// Get the second most recent login (the most recent is the current one)
|
|
||||||
Result<UserLogin> result = r.db(config.getDatabase()).table(TABLE_NAME)
|
|
||||||
.orderBy().optArg("index", r.desc("loginTime"))
|
|
||||||
.filter(r.hashMap("userId", userId))
|
|
||||||
.skip(1).limit(1)
|
|
||||||
.run(connection, UserLogin.class);
|
|
||||||
// Return the second most recent login if exists
|
|
||||||
return result.hasNext() ? result.next() : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<UserLogin> getUserLogins(String userId) {
|
|
||||||
Result<UserLogin> result = r.db(config.getDatabase()).table(TABLE_NAME)
|
|
||||||
.orderBy().optArg("index", r.desc("loginTime"))
|
|
||||||
.filter(r.hashMap("userId", userId))
|
|
||||||
.run(connection, UserLogin.class);
|
|
||||||
return result.toList();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void deleteAllUserLogins(String userId) {
|
|
||||||
r.db(config.getDatabase()).table(TABLE_NAME)
|
|
||||||
.filter(r.hashMap("userId", userId))
|
|
||||||
.delete()
|
|
||||||
.run(connection);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,55 +1,20 @@
|
|||||||
package de.w665.biblenotes.db.repo;
|
package de.w665.biblenotes.db.repo;
|
||||||
|
|
||||||
import com.rethinkdb.RethinkDB;
|
import de.w665.biblenotes.db.entity.User;
|
||||||
import com.rethinkdb.net.Connection;
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
import de.w665.biblenotes.db.RethinkDBConfig;
|
import org.springframework.data.jpa.repository.Modifying;
|
||||||
import de.w665.biblenotes.db.RethinkDBConnector;
|
import org.springframework.data.jpa.repository.Query;
|
||||||
import de.w665.biblenotes.model.User;
|
import org.springframework.data.repository.query.Param;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
import org.springframework.stereotype.Repository;
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
@Repository
|
import java.time.LocalDateTime;
|
||||||
public class UserRepository {
|
import java.util.Optional;
|
||||||
private final RethinkDB r;
|
|
||||||
private final Connection connection;
|
|
||||||
private final RethinkDBConfig config;
|
|
||||||
@Autowired
|
|
||||||
public UserRepository(RethinkDBConnector connector, RethinkDBConfig config) {
|
|
||||||
this.r = connector.getR();
|
|
||||||
this.connection = connector.getConnection();
|
|
||||||
this.config = config;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Optional<User> retrieveUserByUsername(String username) {
|
public interface UserRepository extends JpaRepository<User, Long> {
|
||||||
try {
|
Optional<User> findByUsername(String username);
|
||||||
User user = r.db(config.getDatabase()).table("users")
|
|
||||||
.filter(r.hashMap("username", username))
|
|
||||||
.run(connection, User.class)
|
|
||||||
.next();
|
|
||||||
return Optional.ofNullable(user);
|
|
||||||
} catch (NoSuchElementException e) {
|
|
||||||
return Optional.empty();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void updateLastLoginForUser(String username, Date lastLogin) {
|
@Modifying
|
||||||
r.db(config.getDatabase()).table("users")
|
@Transactional
|
||||||
.filter(r.hashMap("username", username))
|
@Query("UPDATE User u SET u.updatedAt = :lastLogin WHERE u.username = :username")
|
||||||
.update(r.hashMap("lastLogin", lastLogin.getTime()))
|
void updateLastLoginForUser(@Param("username") String username, @Param("lastLogin") LocalDateTime lastLogin);
|
||||||
.run(connection);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void updateUser(User user) {
|
|
||||||
r.db(config.getDatabase()).table("users")
|
|
||||||
.filter(r.hashMap("id", user.getId()))
|
|
||||||
.update(user)
|
|
||||||
.run(connection);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void insertUser(User user) {
|
|
||||||
String optionalUuid = r.uuid().run(connection, String.class).first();
|
|
||||||
user.setId(optionalUuid);
|
|
||||||
r.db(config.getDatabase()).table("users").insert(user).run(connection);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,18 +0,0 @@
|
|||||||
package de.w665.biblenotes.model;
|
|
||||||
|
|
||||||
import lombok.*;
|
|
||||||
|
|
||||||
import java.time.LocalDateTime;
|
|
||||||
|
|
||||||
@Getter
|
|
||||||
@Setter
|
|
||||||
@ToString
|
|
||||||
@NoArgsConstructor
|
|
||||||
@AllArgsConstructor
|
|
||||||
public class User {
|
|
||||||
private String id; // ID is auto mapped by RethinkDB
|
|
||||||
private String username;
|
|
||||||
private String password;
|
|
||||||
private String email;
|
|
||||||
private String role;
|
|
||||||
}
|
|
@ -1,21 +0,0 @@
|
|||||||
package de.w665.biblenotes.model;
|
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import lombok.Getter;
|
|
||||||
import lombok.NoArgsConstructor;
|
|
||||||
import lombok.Setter;
|
|
||||||
|
|
||||||
import java.util.Date;
|
|
||||||
|
|
||||||
@Getter
|
|
||||||
@Setter
|
|
||||||
@NoArgsConstructor
|
|
||||||
@AllArgsConstructor
|
|
||||||
public class UserLogin {
|
|
||||||
String id;
|
|
||||||
String userId;
|
|
||||||
@JsonFormat(timezone = "ETC")
|
|
||||||
Date loginTime;
|
|
||||||
String loginIp;
|
|
||||||
}
|
|
@ -2,8 +2,8 @@ package de.w665.biblenotes.service;
|
|||||||
|
|
||||||
import de.w665.biblenotes.db.repo.UserLoginRepository;
|
import de.w665.biblenotes.db.repo.UserLoginRepository;
|
||||||
import de.w665.biblenotes.db.repo.UserRepository;
|
import de.w665.biblenotes.db.repo.UserRepository;
|
||||||
import de.w665.biblenotes.model.User;
|
import de.w665.biblenotes.db.entity.User;
|
||||||
import de.w665.biblenotes.model.UserLogin;
|
import de.w665.biblenotes.db.entity.UserLogin;
|
||||||
import io.jsonwebtoken.Claims;
|
import io.jsonwebtoken.Claims;
|
||||||
import io.jsonwebtoken.Jwt;
|
import io.jsonwebtoken.Jwt;
|
||||||
import io.jsonwebtoken.Jwts;
|
import io.jsonwebtoken.Jwts;
|
||||||
@ -15,6 +15,7 @@ import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
|||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import javax.crypto.SecretKey;
|
import javax.crypto.SecretKey;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
import java.util.Base64;
|
import java.util.Base64;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
@ -49,18 +50,24 @@ public class AuthenticationService {
|
|||||||
if(expirationTime.length > 0) {
|
if(expirationTime.length > 0) {
|
||||||
this.expirationTime = expirationTime[0];
|
this.expirationTime = expirationTime[0];
|
||||||
}
|
}
|
||||||
Optional<User> optionalUser = userRepository.retrieveUserByUsername(username);
|
log.debug("Authenticating user: {}", username);
|
||||||
|
Optional<User> optionalUser = userRepository.findByUsername(username);
|
||||||
if (optionalUser.isPresent() && passwordEncoder.matches(password, optionalUser.get().getPassword())) {
|
if (optionalUser.isPresent() && passwordEncoder.matches(password, optionalUser.get().getPassword())) {
|
||||||
User user = optionalUser.get();
|
User user = optionalUser.get();
|
||||||
|
|
||||||
userLoginRepository.insertUserLogin(new UserLogin(""/*Auto generated*/, user.getId(), new Date(), remoteAddr));
|
UserLogin userLogin = new UserLogin();
|
||||||
userRepository.updateLastLoginForUser(user.getUsername(), new Date());
|
userLogin.setUserId(user.getId());
|
||||||
|
userLogin.setLoginTime(LocalDateTime.now());
|
||||||
|
userLogin.setLoginIp(remoteAddr);
|
||||||
|
|
||||||
|
userLoginRepository.save(userLogin);
|
||||||
|
userRepository.updateLastLoginForUser(user.getUsername(), LocalDateTime.now());
|
||||||
return generateToken(user);
|
return generateToken(user);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private String generateToken(User username) {
|
private String generateToken(User user) {
|
||||||
long nowMillis = System.currentTimeMillis();
|
long nowMillis = System.currentTimeMillis();
|
||||||
Date now = new Date(nowMillis);
|
Date now = new Date(nowMillis);
|
||||||
Date expiryDate = new Date(nowMillis + expirationTime);
|
Date expiryDate = new Date(nowMillis + expirationTime);
|
||||||
@ -68,8 +75,8 @@ public class AuthenticationService {
|
|||||||
return Jwts.builder()
|
return Jwts.builder()
|
||||||
.subject("SharePulse Authentication Token")
|
.subject("SharePulse Authentication Token")
|
||||||
.issuedAt(now)
|
.issuedAt(now)
|
||||||
.claim("role", username.getRole())
|
.claim("role", user.getRole())
|
||||||
.claim("username", username.getUsername())
|
.claim("username", user.getUsername())
|
||||||
.expiration(expiryDate)
|
.expiration(expiryDate)
|
||||||
.signWith(secretKey)
|
.signWith(secretKey)
|
||||||
.compact();
|
.compact();
|
||||||
|
@ -1,14 +1,15 @@
|
|||||||
spring.application.name=biblenotes
|
spring.application.name=biblenotes
|
||||||
server.port=665
|
server.port=665
|
||||||
|
database.init.create-default-admin-user=true
|
||||||
biblenotes.auto-reset-on-startup=true
|
|
||||||
biblenotes.management.user.username=admin
|
|
||||||
biblenotes.management.user.password=admin
|
|
||||||
|
|
||||||
rethinkdb.host=localhost
|
|
||||||
rethinkdb.port=28015
|
|
||||||
rethinkdb.database=biblenotes
|
|
||||||
|
|
||||||
secureapi.jwt.secret=someSecretChangeMeInProduction
|
secureapi.jwt.secret=someSecretChangeMeInProduction
|
||||||
secureapi.jwt.expiration=86400000
|
secureapi.jwt.expiration=86400000
|
||||||
|
|
||||||
|
spring.datasource.url=jdbc:postgresql://localhost:5432/biblenotes
|
||||||
|
spring.datasource.username=biblenotes
|
||||||
|
spring.datasource.password=ujhfdogiuhfdgiusdfhoviufdnpviusdhdfiuqbfoiudzsfzidfugofduszbdv
|
||||||
|
spring.jpa.hibernate.ddl-auto=update
|
||||||
|
spring.jpa.show-sql=true
|
||||||
|
spring.jpa.database=postgresql
|
||||||
|
|
||||||
|
logging.level.de.w665.biblenotes=DEBUG
|
Loading…
x
Reference in New Issue
Block a user