13편에서는 로그인 API를 구축하는 것까지 해보았다.
로그인 코드를 수정하고 JWT토큰 처리를 해보자
package com.hyeonjoonpark.board_crud.Controller;
import com.hyeonjoonpark.board_crud.Dto.ResponseDto;
import com.hyeonjoonpark.board_crud.Dto.LoginResponseDto;
import com.hyeonjoonpark.board_crud.Dto.LoginDto;
import com.hyeonjoonpark.board_crud.Dto.SignupDto;
import com.hyeonjoonpark.board_crud.Service.AuthService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/api/auth")
public class AuthController {
@Autowired AuthService authService;
@PostMapping("/signUp")
public ResponseDto<?> signUp(@RequestBody SignupDto requestBody) {
ResponseDto<?> result = authService.signUp(requestBody);
return result;
}
@PostMapping("/login")
public ResponseDto<LoginResponseDto> login(@RequestBody LoginDto requestBody) {
ResponseDto<LoginResponseDto> result = authService.login(requestBody);
return result;
}
}
13편에서 했던 코드이다
위 코드에서 다음과 같이
try {
boolean existed = userRepository.existsByUserEmailAndUserPassword(userEmail, userPassword);
if(!existed) {
return ResponseDto.setFailed("Login Info is Wrong");
}
} catch (Exception e) {
return ResponseDto.setFailed("Database Error");
}
UserEntity userEntity = null;
try {
// 값이 존재하면
userEntity = userRepository.findById(userEmail).get(); // 사용자 이메일을 가져옴
} catch(Exception e) {
return ResponseDto.setFailed("Database Error");
}
userEntity.setUserPassword("");
Repository에 접근하는 코드들은 모두 try~catch로 감싸주자
토큰에 실제 값을 넣어보자
Bearer 인증방식과 JsonWebToken을 사용할 것이다.
토큰을 사용하기 위해 의존성을 주입해야한다.
build.gradle
implementation group: 'io.jsonwebtoken', name: 'jjwt', version: '0.9.1'
의존성을 추가해주자
프로젝트 폴더 및에 Security라는 패키지를 생성하고 TokenProvider
클래스를 생성한다.
Security/TokenProvider 클래스를 작성해보자
package com.hyeonjoonpark.board_crud.Security;
import org.springframework.stereotype.Service;
@Service
public class TokenProvider {
private static final String SECURITY_KEY = "jwtsecretkey!@";
public String createJwt(String userEmail) {
}
}
여기서 SECURTITY_KEY는 JWT를 판별하는 secret key를 선언한 것이고
createJwt 메서드는 JWT를 생성하는 메서드로써 userEmail을 인자로 받는다
public String createJwt(String userEmail) {
Date exprTime = Date.from(Instant.now().plus(1, ChronoUnit.HOURS));
return Jwts.builder()
.signWith(SignatureAlgorithm.HS512, SECURITY_KEY)
.setSubject(userEmail)
.setIssuedAt(new Date())
.setExpiration(exprTime)
.compact();
}
Date exprTime = Date.from(Instant.now().plus(1, ChronoUnit.HOURS));
토큰 만료시간을 현재시간의 1시간 후로 설정한다
return Jwts.builder()
.signWith(SignatureAlgorithm.HS512, SECURITY_KEY)
.setSubject(userEmail)
.setIssuedAt(new Date())
.setExpiration(exprTime)
.compact();
.signWith(SignatureAlgorithm.HS512, SECURITY_KEY)
HS512알고리즘과 위에서 선언한 SECURITY_KEY를 이용한다
복호화
public String validateJwt(String token) {
Claims claims = Jwts.parser()
.setSigningKey(SECURITY_KEY) // token을 SECURITY_KEY를 이용해 파싱
.parseClaimsJws(token)
.getBody();
return claims.getSubject(); // token을 파싱해서 토큰 생성할 때 넣은 userEmail을 가져올 수 있다
}
복호화하는 함수이다.
최종코드
package com.hyeonjoonpark.board_crud.Security;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.stereotype.Service;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.Date;
@Service
public class TokenProvider {
private static final String SECURITY_KEY = "jwtsecretkey!@";
// JWT 생성하는 메서드
public String createJwt(String userEmail) {
Date exprTime = Date.from(Instant.now().plus(1, ChronoUnit.HOURS));
return Jwts.builder() // builder를 이용해서 생성
.signWith(SignatureAlgorithm.HS512, SECURITY_KEY) // 암호화 알고리즘, 시크릿 키
.setSubject(userEmail) // JWT의 제목
.setIssuedAt(new Date()) // 생성날짜
.setExpiration(exprTime) // 만료날짜
.compact(); // 생성!
}
// JWT 검증 메서드
public String validateJwt(String token) {
Claims claims = Jwts.parser()
.setSigningKey(SECURITY_KEY) // token을 SECURITY_KEY를 이용해 파싱
.parseClaimsJws(token)
.getBody();
return claims.getSubject(); // token을 파싱해서 토큰 생성할 때 넣은 userEmail을 가져올 수 있다
}
}
우리는 TokenProvider를 서비스로 생성했기 때문에
AuthService
에서 불러올 수 있다.
@Autowired TokenProvider tokenProvider;
String token = tokenProvider.createJwt(userEmail);
전체코드
package com.hyeonjoonpark.board_crud.Service;
import antlr.Token;
import com.hyeonjoonpark.board_crud.Dto.LoginResponseDto;
import com.hyeonjoonpark.board_crud.Dto.ResponseDto;
import com.hyeonjoonpark.board_crud.Dto.LoginDto;
import com.hyeonjoonpark.board_crud.Dto.SignupDto;
import com.hyeonjoonpark.board_crud.Entity.UserEntity;
import com.hyeonjoonpark.board_crud.Repository.UserRepository;
import com.hyeonjoonpark.board_crud.Security.TokenProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class AuthService {
@Autowired UserRepository userRepository;
@Autowired TokenProvider tokenProvider;
public ResponseDto<?> signUp(SignupDto dto) {
String userEmail = dto.getUserEmail();
String userPassword = dto.getUserPassword();
String userPasswordCheck = dto.getUserPasswordCheck();
// email 중복 확인
try {
if(userRepository.existsById(userEmail)) { // userEmail이 존재하는지 확인 -> 존재 시 true 존재하지 않으면 false 반환
return ResponseDto.setFailed("Existed Email!");
}
} catch (Exception e) {
return ResponseDto.setFailed("Database Error");
}
if(!userPassword.equals(userPasswordCheck)) {
return ResponseDto.setFailed("Password is Wrong!");
} // userPassword와 userPasswordCheck가 일치하지 않으면
UserEntity userEntity = new UserEntity(dto); // UserEntity 생성
try {
// UserRepository를 이용해서 DB에 Entity 저쟝
userRepository.save(userEntity);
} catch (Exception e) {
ResponseDto.setFailed("Database Error");
}
return ResponseDto.setSuccess("SignUp Success!", null);
}
public ResponseDto<LoginResponseDto> login(LoginDto dto) {
String userEmail = dto.getUserEmail();
String userPassword = dto.getUserPassword();
try {
boolean existed = userRepository.existsByUserEmailAndUserPassword(userEmail, userPassword);
if(!existed) {
return ResponseDto.setFailed("Login Info is Wrong");
}
} catch (Exception e) {
return ResponseDto.setFailed("Database Error");
}
UserEntity userEntity = null;
try {
// 값이 존재하면
userEntity = userRepository.findById(userEmail).get(); // 사용자 이메일을 가져옴
} catch(Exception e) {
return ResponseDto.setFailed("Database Error");
}
userEntity.setUserPassword("");
String token = tokenProvider.createJwt(userEmail);
int exprTime = 3600000; // 한 시간
LoginResponseDto loginResponseDto = new LoginResponseDto(token, exprTime, userEntity);
return ResponseDto.setSuccess("Login Success", loginResponseDto);
}
}
포스트맨으로 테스트하면 정상적으로 토큰이 생성되는 것을 알 수 있다