jjwt에 대한 설명을 먼저 보고오자
package org.example.jwt.Service.JWT;
@Service
public class JWTService {
// 서명 비밀키로 민감정보이니 잘 관리해야 한다
// 터미널에 `openssl rand -hex 32` 명령어 입력시 랜덤한 값을 얻을수 있다.
private static final String signatureSecretKey = "c3ByaW5nYm9vdC1qd3QtdHV0b3JpYWwtc3ByaW5nYm9vdC1qd3QtdHV0b3JpYWwtc3ByaW5nYm9vdC1qd3QtdHV0b3JpYWwK";
// 인코딩된 서명키가 만들어 진다.( 비밀키만 같다면 항상 같다 )
private SecretKey key = Keys.hmacShaKeyFor(signatureSecretKey.getBytes(StandardCharsets.UTF_8));
// Create JWT Token
public String createJWT(Long memberId) {
return Jwts.builder()
// 페이로드 정보
.claim("memberId", memberId)
// 발행 일
.issuedAt(new Date())
// 하루 동안 유효
.expiration(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 24L))
// 서명키로 서명
.signWith(key)
.compact();
}
// Header 에서 JWT Token 추출 "Authorization: {JWT}"
public String getJWT() {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes())
.getRequest();
String token = request.getHeader("Authorization");
System.out.println("token = " + token);
return token;
}
// JWT Token 을 이용해 memberId 추출
public Long getMemberId() {
String accessToken = getJWT();
// 적당히 여기서 예외처리해도 된다.
if (accessToken == null) {
return null;
}
if (accessToken.isEmpty()) {
return null;
}
Jws<Claims> jws;
try {
jws = Jwts.parser()
.verifyWith(key)
.build()
.parseSignedClaims(accessToken);
} catch (JwtException e) {
throw new RuntimeException(e);
}
// memberId 로 걸었던 클레임을 가져온다.
return jws.getPayload()
.get("memberId", Long.class);
}
}
@Entity
@Builder
@AllArgsConstructor
@DynamicInsert
@DynamicUpdate
@NoArgsConstructor
@Getter
public class Member extends BaseEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false, length = 20)
private String username;
@Column(nullable = false, length = 20)
private String password;
}
@RestController
@RequiredArgsConstructor
@RequestMapping("/members")
public class MemberController {
private final MemberQueryService memberQueryService;
private final MemberCommandService memberCommandService;
private final JWTService jwtService;
// 회원가입 Post 요청이다.
@PostMapping("/signup")
public MemberResponseDTO.MemberCreateResponseDTO signUp(
// 회원가입은 username과 password를 받는다.
@RequestBody MemberRequestDTO.MemberCreateRequestDTO request
) {
// 회원가입을 하면 Member가 생성된다.
Member member = memberCommandService.createMember(request);
// 회원가입을 하면 JWT가 생성된다.
String jwt = jwtService.createJWT(member.getId());
// 생성한 Member와 JWT를 반환한다.
return MemberConverter.toMemberCreateResponseDTO(member,jwt);
}
// 로그인 Post 요청이다.
@PostMapping("/login")
public MemberResponseDTO.MemberLoginResponseDTO login(
// 로그인은 username과 password를 받는다.
@RequestBody MemberRequestDTO.MemberLoginRequestDTO request
) {
// 로그인을 하면 username, password가 일치하는 Member를 찾는다.
// username, password 가 일치 하지 않는 로직은 적절히 처리해야 한다.
Member member = memberQueryService.findMemberByUsernameAndPassword(request.getUsername(), request.getPassword());
// 로그인을 하면 JWT가 생성된다.
String jwt = jwtService.createJWT(member.getId());
// 생성한 Member와 JWT를 반환한다.
return MemberConverter.toMemberLoginResponseDTO(member,jwt);
}
// 유저 정보를 조회하는 Get 요청이다.
@GetMapping("{memberId}")
public MemberResponseDTO.MemberPreviewDTO findMemberById(
// 유저 정보를 조회하려면 memberId를 받아야 한다.
@PathVariable Long memberId
) {
// Header에 있는 토큰을 통해 memberId를 가져온다.
Long memberIdFromToken = jwtService.getMemberId();
// 만약 토큰의 memberId와 요청의 memberId가 다르다면
if (!memberId.equals(memberIdFromToken)) {
// 권한이 없다는 RuntimeException을 던진다.
throw new RuntimeException("권한이 없습니다.");
}
// memberId로 Member를 찾아 MemberPreviewDTO로 변환하여 반환한다.
return MemberConverter.toMemberPreviewDTO(memberQueryService.findMemberById(memberId));
}
}
signup
login
get member info
Authorization 헤더값을 넣어야 인증된다.
만약 권한이 없거나 유효시간이 지났다면
아래와 같이 에러가 발생한다.