so isses
This commit is contained in:
parent
74967d1cfa
commit
f33d798663
8 changed files with 121 additions and 46 deletions
5
pom.xml
5
pom.xml
|
|
@ -26,8 +26,9 @@
|
||||||
<artifactId>spring-boot-starter-web</artifactId>
|
<artifactId>spring-boot-starter-web</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>com.auth0</groupId>
|
||||||
<artifactId>spring-boot-starter-security</artifactId>
|
<artifactId>java-jwt</artifactId>
|
||||||
|
<version>4.2.1</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.mysql</groupId>
|
<groupId>com.mysql</groupId>
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
package me.jweissen.aeticket.dto.response;
|
||||||
|
|
||||||
|
public record LoginResponseDto(String token) {
|
||||||
|
}
|
||||||
|
|
@ -4,21 +4,17 @@ import jakarta.persistence.*;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.NonNull;
|
import lombok.NonNull;
|
||||||
import lombok.Setter;
|
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;
|
import java.util.List;
|
||||||
|
|
||||||
@Entity
|
@Entity
|
||||||
@Table
|
@Table
|
||||||
@Getter
|
@Getter
|
||||||
@Setter
|
@Setter
|
||||||
public class User implements UserDetails {
|
public class User {
|
||||||
@Id
|
@Id
|
||||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||||
private int id;
|
private Long id;
|
||||||
|
|
||||||
@Column(nullable = false)
|
@Column(nullable = false)
|
||||||
@NonNull
|
@NonNull
|
||||||
|
|
@ -36,45 +32,16 @@ public class User implements UserDetails {
|
||||||
@NonNull
|
@NonNull
|
||||||
private String password;
|
private String password;
|
||||||
|
|
||||||
@Column(nullable = false)
|
@Column
|
||||||
@NonNull
|
@NonNull
|
||||||
private Boolean admin;
|
private String token;
|
||||||
|
|
||||||
|
@Column(nullable = false)
|
||||||
|
@Enumerated(EnumType.ORDINAL)
|
||||||
|
@NonNull
|
||||||
|
private Role role;
|
||||||
|
|
||||||
@OneToMany(mappedBy = "user")
|
@OneToMany(mappedBy = "user")
|
||||||
@JoinColumn(nullable = false)
|
@JoinColumn(nullable = false)
|
||||||
private List<Cart> carts;
|
private List<Cart> 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -4,4 +4,5 @@ import me.jweissen.aeticket.model.User;
|
||||||
import org.springframework.data.jpa.repository.JpaRepository;
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
|
||||||
public interface UserRepository extends JpaRepository<User, Integer> {
|
public interface UserRepository extends JpaRepository<User, Integer> {
|
||||||
|
User findByEmail(String email);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
35
src/main/java/me/jweissen/aeticket/service/AuthService.java
Normal file
35
src/main/java/me/jweissen/aeticket/service/AuthService.java
Normal file
|
|
@ -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<LoginResponseDto> 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));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
57
src/main/java/me/jweissen/aeticket/service/JwtService.java
Normal file
57
src/main/java/me/jweissen/aeticket/service/JwtService.java
Normal file
|
|
@ -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<Long> 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());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -10,9 +10,11 @@ import java.util.List;
|
||||||
@Service
|
@Service
|
||||||
public class UserService {
|
public class UserService {
|
||||||
private final UserRepository userRepository;
|
private final UserRepository userRepository;
|
||||||
|
private final JwtService jwtService;
|
||||||
|
|
||||||
public UserService(UserRepository userRepository) {
|
public UserService(UserRepository userRepository, JwtService jwtService) {
|
||||||
this.userRepository = userRepository;
|
this.userRepository = userRepository;
|
||||||
|
this.jwtService = jwtService;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static UserResponseDto toDto(User user) {
|
public static UserResponseDto toDto(User user) {
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
Reference in a new issue