diff --git a/pom.xml b/pom.xml
index 1f7ab15..f26c95b 100644
--- a/pom.xml
+++ b/pom.xml
@@ -26,8 +26,9 @@
spring-boot-starter-web
- org.springframework.boot
- spring-boot-starter-security
+ com.auth0
+ java-jwt
+ 4.2.1
com.mysql
diff --git a/src/main/java/me/jweissen/aeticket/dto/response/LoginResponseDto.java b/src/main/java/me/jweissen/aeticket/dto/response/LoginResponseDto.java
new file mode 100644
index 0000000..07444a4
--- /dev/null
+++ b/src/main/java/me/jweissen/aeticket/dto/response/LoginResponseDto.java
@@ -0,0 +1,4 @@
+package me.jweissen.aeticket.dto.response;
+
+public record LoginResponseDto(String token) {
+}
diff --git a/src/main/java/me/jweissen/aeticket/model/User.java b/src/main/java/me/jweissen/aeticket/model/User.java
index 95b563e..9432d09 100644
--- a/src/main/java/me/jweissen/aeticket/model/User.java
+++ b/src/main/java/me/jweissen/aeticket/model/User.java
@@ -4,21 +4,17 @@ import jakarta.persistence.*;
import lombok.Getter;
import lombok.NonNull;
import lombok.Setter;
-import org.springframework.security.core.GrantedAuthority;
-import org.springframework.security.core.authority.SimpleGrantedAuthority;
-import org.springframework.security.core.userdetails.UserDetails;
-import java.util.Collection;
import java.util.List;
@Entity
@Table
@Getter
@Setter
-public class User implements UserDetails {
+public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
- private int id;
+ private Long id;
@Column(nullable = false)
@NonNull
@@ -36,45 +32,16 @@ public class User implements UserDetails {
@NonNull
private String password;
- @Column(nullable = false)
+ @Column
@NonNull
- private Boolean admin;
+ private String token;
+
+ @Column(nullable = false)
+ @Enumerated(EnumType.ORDINAL)
+ @NonNull
+ private Role role;
@OneToMany(mappedBy = "user")
@JoinColumn(nullable = false)
private List carts;
-
- @Enumerated(EnumType.STRING)
- private Role role;
-
- @Override
- public Collection extends GrantedAuthority> getAuthorities() {
- return List.of(new SimpleGrantedAuthority(role.name()));
- }
-
- @Override
- public String getUsername() {
- return email;
- }
-
- @Override
- public boolean isAccountNonExpired() {
- return true;
- }
-
- @Override
- public boolean isAccountNonLocked() {
- return true;
- }
-
- @Override
- public boolean isCredentialsNonExpired() {
- return true;
- }
-
- @Override
- public boolean isEnabled() {
- return true;
- }
-}
-}
+}
\ No newline at end of file
diff --git a/src/main/java/me/jweissen/aeticket/repository/UserRepository.java b/src/main/java/me/jweissen/aeticket/repository/UserRepository.java
index 6be1940..24cd7df 100644
--- a/src/main/java/me/jweissen/aeticket/repository/UserRepository.java
+++ b/src/main/java/me/jweissen/aeticket/repository/UserRepository.java
@@ -4,4 +4,5 @@ import me.jweissen.aeticket.model.User;
import org.springframework.data.jpa.repository.JpaRepository;
public interface UserRepository extends JpaRepository {
+ User findByEmail(String email);
}
diff --git a/src/main/java/me/jweissen/aeticket/service/AuthService.java b/src/main/java/me/jweissen/aeticket/service/AuthService.java
new file mode 100644
index 0000000..e8487a9
--- /dev/null
+++ b/src/main/java/me/jweissen/aeticket/service/AuthService.java
@@ -0,0 +1,35 @@
+package me.jweissen.aeticket.service;
+
+import me.jweissen.aeticket.dto.response.LoginResponseDto;
+import me.jweissen.aeticket.model.User;
+import me.jweissen.aeticket.repository.UserRepository;
+import org.springframework.stereotype.Service;
+
+import java.util.Optional;
+
+@Service
+public class AuthService {
+ private final JwtService jwtService;
+ private final UserService userService;
+ private final UserRepository userRepository;
+
+ public AuthService(JwtService jwtService, UserService userService, UserRepository userRepository) {
+ this.jwtService = jwtService;
+ this.userService = userService;
+ this.userRepository = userRepository;
+ }
+
+ public Optional login(String username, String password) {
+ User user = userRepository.findByEmail(username);
+ // user not found or passwords don't match
+ if (user == null || !user.getPassword().equals(password)) {
+ return Optional.empty();
+ }
+ String token = jwtService.generateToken(user.getId());
+ user.setToken(token);
+ userRepository.save(user);
+ return Optional.of(new LoginResponseDto(username));
+ }
+
+
+}
diff --git a/src/main/java/me/jweissen/aeticket/service/JwtService.java b/src/main/java/me/jweissen/aeticket/service/JwtService.java
new file mode 100644
index 0000000..866605d
--- /dev/null
+++ b/src/main/java/me/jweissen/aeticket/service/JwtService.java
@@ -0,0 +1,57 @@
+package me.jweissen.aeticket.service;
+
+import com.auth0.jwt.JWT;
+import com.auth0.jwt.JWTVerifier;
+import com.auth0.jwt.algorithms.Algorithm;
+import com.auth0.jwt.exceptions.JWTVerificationException;
+import com.auth0.jwt.interfaces.Claim;
+import com.auth0.jwt.interfaces.DecodedJWT;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Service;
+
+import java.util.Date;
+import java.util.Optional;
+
+@Service
+public class JwtService {
+ @Value("${token.secret}")
+ private String secret;
+ @Value("${token.validForHours}")
+ private Long tokenValidForHours;
+
+ private final JWTVerifier jwtVerifier;
+ private final Algorithm algorithm;
+ private final String userIdClaimKey = "userId";
+ private final Long tokenValidForMillis;
+
+ public JwtService() {
+ tokenValidForMillis = 1000L * 3600 * tokenValidForHours;
+ algorithm = Algorithm.HMAC256(secret);
+ jwtVerifier = JWT.require(algorithm).build();
+ }
+
+ public String generateToken(Long userId) {
+ return JWT.create()
+ .withSubject("aeticket user token")
+ .withClaim(userIdClaimKey , userId)
+ .withIssuedAt(new Date())
+ .withExpiresAt(new Date(System.currentTimeMillis() + tokenValidForMillis))
+ .sign(algorithm);
+ }
+
+ public Optional getUserId(String token) {
+ DecodedJWT decodedJWT;
+ try {
+ decodedJWT = jwtVerifier.verify(token);
+ } catch (JWTVerificationException e) {
+ // token not valid
+ return Optional.empty();
+ }
+ // token expired
+ if (decodedJWT.getExpiresAt().before(new Date())) {
+ return Optional.empty();
+ }
+ Claim claim = decodedJWT.getClaim(userIdClaimKey);
+ return Optional.of(claim.asLong());
+ }
+}
diff --git a/src/main/java/me/jweissen/aeticket/service/UserService.java b/src/main/java/me/jweissen/aeticket/service/UserService.java
index d22f693..7da5f4d 100644
--- a/src/main/java/me/jweissen/aeticket/service/UserService.java
+++ b/src/main/java/me/jweissen/aeticket/service/UserService.java
@@ -10,9 +10,11 @@ import java.util.List;
@Service
public class UserService {
private final UserRepository userRepository;
+ private final JwtService jwtService;
- public UserService(UserRepository userRepository) {
+ public UserService(UserRepository userRepository, JwtService jwtService) {
this.userRepository = userRepository;
+ this.jwtService = jwtService;
}
public static UserResponseDto toDto(User user) {
diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml
index e69de29..09a8c35 100644
--- a/src/main/resources/application.yml
+++ b/src/main/resources/application.yml
@@ -0,0 +1,8 @@
+spring:
+ datasource:
+ username: my
+ password: ticket
+ url: 'jdbc:mysql://localhost:4306/myticket'
+token:
+ secret: "RATP loves Laravel more than Symfony"
+ validForHours: 24
\ No newline at end of file