Skip to content

Commit

Permalink
Merge pull request #10 from hokkung/hok/refactor-jwt
Browse files Browse the repository at this point in the history
refactor jwt
  • Loading branch information
hokkung authored Apr 6, 2024
2 parents 13b38af + 0ea11a3 commit 59d198b
Show file tree
Hide file tree
Showing 14 changed files with 171 additions and 73 deletions.
3 changes: 2 additions & 1 deletion src/main/java/com/leo/user/UserApplication.java
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
package com.leo.user;

import com.leo.user.config.JwtProperties;
import com.leo.user.config.RSAKeyProperties;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.boot.context.properties.EnableConfigurationProperties;

@EntityScan("com.leo.user.domain.user")
@EnableConfigurationProperties(RSAKeyProperties.class)
@EnableConfigurationProperties({RSAKeyProperties.class, JwtProperties.class})
@SpringBootApplication
public class UserApplication {

Expand Down
7 changes: 5 additions & 2 deletions src/main/java/com/leo/user/common/security/JwtService.java
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
package com.leo.user.common.security;

import org.springframework.security.core.Authentication;
import com.leo.user.domain.user.User;
import com.leo.user.model.auth.JwtToken;

public interface JwtService {

// String extractUsername(String token);
//
// boolean IsTokenValid(String token, UserDetails userDetails);

String generateToken(Authentication authentication);
JwtToken generateToken(String name);

JwtToken generateToken(User user);
}
48 changes: 33 additions & 15 deletions src/main/java/com/leo/user/common/security/JwtServiceImpl.java
Original file line number Diff line number Diff line change
@@ -1,47 +1,65 @@
package com.leo.user.common.security;

import com.leo.user.common.util.ClockUtils;
import com.leo.user.config.JwtProperties;
import com.leo.user.domain.user.User;
import com.leo.user.model.auth.JwtToken;
import lombok.Setter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.oauth2.jwt.JwtClaimsSet;
import org.springframework.security.oauth2.jwt.JwtDecoder;
import org.springframework.security.oauth2.jwt.JwtEncoder;
import org.springframework.security.oauth2.jwt.JwtEncoderParameters;
import org.springframework.stereotype.Service;

import java.time.Instant;
import java.util.Date;
import java.util.Set;
import java.util.stream.Collectors;


@Service
@Setter
public class JwtServiceImpl implements JwtService {

@Value("${jwt.expiration-time-in-minute:60}")
private long jwtExpirationTimeInMinute;
@Autowired
private JwtProperties jwtProperties;

@Autowired
@Setter
private JwtDecoder jwtDecoder;

@Autowired
@Setter
private JwtEncoder jwtEncoder;

@Override
public String generateToken(Authentication auth) {
String scope = auth.getAuthorities().stream()
.map(GrantedAuthority::getAuthority)
.collect(Collectors.joining(" "));
public JwtToken generateToken(String name) {
return generateToken(name, Set.of());
}

@Override
public JwtToken generateToken(User user) {
return generateToken(user.getEmail(), user.getRoles().stream().map(Enum::name).collect(Collectors.toSet()));
}

private JwtToken generateToken(String name, Set<String> roles) {
Instant current = ClockUtils.getCurrent();
Instant expirationTime = getExpirationTime(current);

JwtClaimsSet claims = JwtClaimsSet.builder()
.issuedAt(new Date().toInstant())
.subject(auth.getName())
.claim("roles", scope)
.issuedAt(current)
.expiresAt(expirationTime)
.subject(name)
.claim("roles", String.join(" ", roles))
.build();

return jwtEncoder.encode(JwtEncoderParameters.from(claims)).getTokenValue();
return new JwtToken(
jwtEncoder.encode(JwtEncoderParameters.from(claims)).getTokenValue(),
new Date(expirationTime.toEpochMilli())
);
}

private Instant getExpirationTime(Instant current) {
return current.plusMillis(jwtProperties.expirationTimeInMinute() * 60 * 1000);
}

//
Expand Down
20 changes: 19 additions & 1 deletion src/main/java/com/leo/user/common/util/ClockUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,29 @@
import lombok.experimental.UtilityClass;

import java.time.Clock;
import java.time.Instant;
import java.util.Date;

@UtilityClass
public class ClockUtils {
private static final Clock SYSTEM_CLOCK = Clock.systemUTC();
public static Instant getCurrent() {
return Instant.now(SYSTEM_CLOCK);
}

public static Date current() {
return Date.from(Clock.systemDefaultZone().instant());
return Date.from(Instant.now(SYSTEM_CLOCK));
}

public static boolean isBefore(Instant instant) {
return instant.isBefore(getCurrent());
}

public static boolean isAfter(Instant instant) {
return instant.isAfter(getCurrent());
}

public static boolean isNow(Instant instant) {
return instant.equals(getCurrent());
}
}
12 changes: 12 additions & 0 deletions src/main/java/com/leo/user/config/JwtProperties.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.leo.user.config;

import org.springframework.boot.context.properties.ConfigurationProperties;

@ConfigurationProperties(prefix = "jwt")
public record JwtProperties(
long expirationTimeInMinute
) {
public JwtProperties() {
this(1);
}
}
5 changes: 4 additions & 1 deletion src/main/java/com/leo/user/config/RSAKeyProperties.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,7 @@
import java.security.interfaces.RSAPublicKey;

@ConfigurationProperties(prefix = "jwt")
public record RSAKeyProperties(RSAPublicKey rsaPublicKey, RSAPrivateKey rsaPrivateKey) {}
public record RSAKeyProperties(
RSAPublicKey rsaPublicKey,
RSAPrivateKey rsaPrivateKey
) {}
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
package com.leo.user.controller.auth;


import com.leo.user.domain.user.User;
import com.leo.user.mapper.user.UserMapper;
import com.leo.user.model.auth.AuthenticationResponseDto;
import com.leo.user.model.auth.AuthenticationResult;
import com.leo.user.model.auth.LoginResponseDto;
import com.leo.user.model.auth.RegisterRequest;
import com.leo.user.service.auth.AuthenticationService;
Expand All @@ -23,16 +22,22 @@ public class AuthenticationController {
private AuthenticationService authenticationService;

@PostMapping("/register")
public AuthenticationResponseDto register(@RequestBody RegisterRequest request) {
User user = authenticationService.register(request);
public LoginResponseDto register(@RequestBody RegisterRequest request) {
AuthenticationResult res = authenticationService.register(request);

return AuthenticationResponseDto.builder().user(UserMapper.INSTANCE.toUserDTO(user)).build();
return new LoginResponseDto(
UserMapper.INSTANCE.toUserDTO(res.user()),
res.token(),
res.tokenExpirationTime());
}

@PostMapping("/login")
public LoginResponseDto login(@RequestBody RegisterRequest request) {
String token = authenticationService.login(request);
AuthenticationResult res = authenticationService.login(request);

return LoginResponseDto.builder().token(token).build();
return new LoginResponseDto(
UserMapper.INSTANCE.toUserDTO(res.user()),
res.token(),
res.tokenExpirationTime());
}
}

This file was deleted.

12 changes: 12 additions & 0 deletions src/main/java/com/leo/user/model/auth/AuthenticationResult.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.leo.user.model.auth;

import com.leo.user.domain.user.User;

import java.util.Date;

public record AuthenticationResult(
User user,
String token,
Date tokenExpirationTime
){
}
9 changes: 9 additions & 0 deletions src/main/java/com/leo/user/model/auth/JwtToken.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.leo.user.model.auth;


import java.util.Date;

public record JwtToken (
String token,
Date tokenExpirationTime
){}
15 changes: 8 additions & 7 deletions src/main/java/com/leo/user/model/auth/LoginResponseDto.java
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
package com.leo.user.model.auth;

import lombok.Builder;
import lombok.Data;
import com.leo.user.model.user.UserDto;

@Data
@Builder
public class LoginResponseDto {
private String token;
}
import java.util.Date;

public record LoginResponseDto(
UserDto user,
String token,
Date tokenExpiredTime
) {}
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
package com.leo.user.service.auth;

import com.leo.user.domain.user.User;
import com.leo.user.model.auth.AuthenticationResult;
import com.leo.user.model.auth.RegisterRequest;

public interface AuthenticationService {
User register(RegisterRequest registerRequest);
AuthenticationResult register(RegisterRequest registerRequest);

String login(RegisterRequest request);
AuthenticationResult login(RegisterRequest request);
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
package com.leo.user.service.auth;


import com.leo.user.common.exception.EntityNotFoundException;
import com.leo.user.common.security.JwtService;
import com.leo.user.domain.user.Gender;
import com.leo.user.domain.user.User;
import com.leo.user.model.auth.AuthenticationResult;
import com.leo.user.model.auth.JwtToken;
import com.leo.user.model.auth.RegisterRequest;
import com.leo.user.model.user.CreateOrUpdateUserForm;
import com.leo.user.repository.user.UserRepository;
Expand All @@ -12,21 +15,17 @@
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import java.util.Optional;

@Service
@Setter
public class AuthenticationServiceImpl implements AuthenticationService {

@Autowired
@Setter
private UserRepository userRepository;

@Autowired
@Setter
private PasswordEncoder passwordEncoder;

@Autowired
private AuthenticationManager authenticationManager;

Expand All @@ -37,21 +36,38 @@ public class AuthenticationServiceImpl implements AuthenticationService {
private UserCrudService userCrudService;

@Override
public User register(RegisterRequest request) {
public AuthenticationResult register(RegisterRequest request) {
CreateOrUpdateUserForm form = CreateOrUpdateUserForm
.builder()
.name(request.getName())
.email(request.getEmail())
.password(request.getPassword())
.gender(Gender.valueOf(request.getGender()))
.build();
return userCrudService.create(form);
User user = userCrudService.create(form);
return generateToken(user);
}

@Override
public String login(RegisterRequest request) {
Authentication auth = authenticationManager.authenticate(
new UsernamePasswordAuthenticationToken(request.getEmail(), request.getPassword()));
public AuthenticationResult login(RegisterRequest request) {
authenticationManager.authenticate(
new UsernamePasswordAuthenticationToken(request.getEmail(), request.getPassword())
);

Optional<User> optionalUser = userRepository.findByEmail(request.getEmail());
if (optionalUser.isEmpty()) {
throw new EntityNotFoundException();
}

return jwtService.generateToken(auth);}
return generateToken(optionalUser.get());
}

private AuthenticationResult generateToken(User user) {
JwtToken jwtToken = jwtService.generateToken(user);
return new AuthenticationResult(
user,
jwtToken.token(),
jwtToken.tokenExpirationTime()
);
}
}
Loading

0 comments on commit 59d198b

Please sign in to comment.