반응형
지난 포스팅에서 jwt가 무엇인지 살펴보았습니다. (https://roomconerdeveloper.tistory.com/183)
이제 jwt를 발급하는 기능을 SpringBoot로 구현해 보겠습니다.
소스코드는 github에 있습니다.
https://github.com/lsm7179/spring-eCommerce-study/tree/step1
사용한 버전 및 의존성
사용한 버전 다음과 같습니다.
* SpringBoot: 3.3.2
* Java: 22
gradle 의존성
plugins {
id 'java'
id 'org.springframework.boot' version '3.3.2'
id 'io.spring.dependency-management' version '1.1.6'
}
group = 'my.study'
version = '0.0.1-SNAPSHOT'
java {
toolchain {
languageVersion = JavaLanguageVersion.of(22)
}
}
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'io.jsonwebtoken:jjwt:0.12.6'
runtimeOnly 'com.h2database:h2'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
}
tasks.named('test') {
useJUnitPlatform()
}
로그인을 한후 토큰을 반환하는 간단한 시퀀스 다이어그램입니다.
Code
Controller
@RestController
public class MemberController {
private final MemberService memberService;
public MemberController(MemberService memberService) {
this.memberService = memberService;
}
@PostMapping("/join")
public ResponseEntity<Long> join(@RequestBody final JoinRequest joinRequest) {
Long memberId = memberService.join(joinRequest);
return ResponseEntity
.created(URI.create("/login"))
.body(memberId);
}
@PostMapping("/login")
public ResponseEntity<String> login(@RequestBody final LoginRequest loginRequest) {
return ResponseEntity.ok(memberService.login(loginRequest));
}
}
Serivce 계층
@Service
@Transactional(readOnly = true)
public class MemberService {
private final MemberRepository memberRepository;
private final JwtGenerator jwtGenerator;
public MemberService(MemberRepository memberRepository, JwtGenerator jwtGenerator) {
this.memberRepository = memberRepository;
this.jwtGenerator = jwtGenerator;
}
@Transactional
public Long join(JoinRequest joinRequest) {
Member createMember = memberRepository.save(joinRequest.toEntity());
return createMember.getId();
}
public String login(LoginRequest loginRequest) {
Member member = memberRepository.findByEmailAndPassword(loginRequest.getEmail(), loginRequest.getPassword())
.orElseThrow(() -> new IllegalArgumentException("이메일과 비밀번호를 확인해주세요."));
return jwtGenerator.generateToken(member);
}
}
repository는 간단한 단일멤버조회만 있습니다.
JwtGenerater
토큰을 발급하는 기능을 하는 jwtgenerater 입니다.
나중에 토큰 확인하는 기능도 추가할 예정입니다.
@Component
public class JwtGenerator {
private final String secretKeyValue;
private final long expiration;
private final SecretKey secretKey;
public JwtGenerator(@Value("${jwt.secret}") String secretKey
, @Value("${jwt.expiration}") long expiration) {
this.secretKeyValue = secretKey;
this.expiration = expiration;
this.secretKey = Keys.hmacShaKeyFor(Decoders.BASE64.decode(secretKey));
}
public String generateToken(Member member) {
return Jwts.builder()
.claim("id", member.getId())
.claim("email", member.getEmail())
.claim("name", member.getName())
.issuedAt(new Date(System.currentTimeMillis()))
.expiration(new Date(System.currentTimeMillis() + expiration))
.signWith(secretKey, Jwts.SIG.HS512)
.compact();
}
}
test 코드
package my.study.springecommercestudy.controller;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import java.util.HashMap;
import java.util.Map;
import static org.assertj.core.api.Assertions.assertThat;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@SpringBootTest
@AutoConfigureMockMvc
class MemberControllerTest {
@Autowired
private MockMvc mockMvc;
@Autowired
private ObjectMapper objectMapper;
@DisplayName("회원가입")
@Test
@Order(0)
void create() throws Exception {
Map<String, String> joinRequest = new HashMap<>();
joinRequest.put("email", "test@test.com");
joinRequest.put("password", "1234!");
joinRequest.put("name", "이승민");
MvcResult mvcResult = mockMvc.perform(post("/join")
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(joinRequest)))
.andExpect(status().isCreated())
.andDo(print())
.andReturn();
String response = mvcResult.getResponse().getContentAsString();
assertThat(response).isNotBlank();
}
@DisplayName("로그인")
@Test
@Order(1)
void join() throws Exception {
Map<String, String> joinRequest = new HashMap<>();
joinRequest.put("email", "test@test.com");
joinRequest.put("password", "1234!");
MvcResult mvcResult = mockMvc.perform(post("/login")
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(joinRequest)))
.andExpect(status().isOk())
.andDo(print())
.andReturn();
String response = mvcResult.getResponse().getContentAsString();
assertThat(response).isNotBlank();
}
}
이렇게 jwt 발급기능을 구현했습니다.
다음 포스트에서 발급한 토큰 유효성검사와 토큰으로 member 정보를 받아서 처리하는 기능을 개발해보겠습니다.
반응형
'프로그래밍 > Java & Spring' 카테고리의 다른 글
SpringBoot Jwt토큰 유효성검사, member 정보를 받아서 처리하는 기능 구현 (0) | 2024.10.07 |
---|---|
JWT란 무엇인가? (0) | 2024.08.07 |
Spring Cloud Service Discorvery (0) | 2023.03.25 |
gradle test코드를 패키지 단위로 제외시키는 방법 (0) | 2022.09.16 |
CompletableFuture와 daemon Thread (0) | 2022.09.02 |
댓글