반응형
지난 포스팅에서는 jwt인증기능을 구현해봤습니다.(https://roomconerdeveloper.tistory.com/184)
이번엔 jwt토큰 유효성검사, member정보를 받아오는api를 구현해 보겠습니다.
소스코드는 github에 있습니다.
https://github.com/lsm7179/spring-eCommerce-study/tree/step2
로그인 한 유저가 내정보를 가져오는 간단한 시퀀스 다이어 그램입니다.
Code
package my.study.springecommercestudy.config.jwt;
import java.lang.annotation.*;
@Target({ ElementType.PARAMETER, ElementType.ANNOTATION_TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface JwtAuthorization {
boolean required() default true;
}
@Component
public class JwtAuthorizationArgumentResolver implements HandlerMethodArgumentResolver {
private final Logger log = LoggerFactory.getLogger(this.getClass().getSimpleName());
private final JwtGenerator jwtGenerator;
public JwtAuthorizationArgumentResolver(JwtGenerator jwtGenerator) {
this.jwtGenerator = jwtGenerator;
}
// @JwtAuthorization 어노테이션이 있을 경우 동작
@Override
public boolean supportsParameter(MethodParameter parameter) {
return parameter.hasParameterAnnotation(JwtAuthorization.class);
}
@Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
HttpServletRequest httpServletRequest = webRequest.getNativeRequest(HttpServletRequest.class);
if (httpServletRequest != null) {
String token = httpServletRequest.getHeader("Authorization");
if (Objects.nonNull(token) && !token.isBlank()) {
if (jwtGenerator.validateToken(token)) {
return jwtGenerator.extractClaims(token);
}
}
JwtAuthorization annotation = parameter.getParameterAnnotation(JwtAuthorization.class);
if (annotation != null && !annotation.required()) {
return Member.emptyMember();
}
}
throw new RuntimeException("토큰 없음");
}
}
package my.study.springecommercestudy.config.jwt;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.io.Decoders;
import io.jsonwebtoken.security.Keys;
import my.study.springecommercestudy.domain.Member;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import javax.crypto.SecretKey;
import java.util.Date;
@Component
public class JwtGenerator {
private final long expiration;
private final SecretKey secretKey;
public JwtGenerator(@Value("${jwt.secret}") String secretKey
, @Value("${jwt.expiration}") long expiration) {
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();
}
public Member extractClaims(String token) {
Claims claims = Jwts.parser()
.verifyWith(secretKey)
.build()
.parseSignedClaims(removeBearer(token))
.getPayload();
String email = (String) claims.getOrDefault("email", "");
Long id = (Long) claims.getOrDefault("id", 0L);
String name = (String) claims.getOrDefault("name", "");
return new Member(id, email, name);
}
public boolean validateToken(String token) {
return !Jwts.parser()
.verifyWith(secretKey)
.build()
.parseSignedClaims(removeBearer(token))
.getPayload()
.getExpiration()
.before(new Date());
}
private String removeBearer(String token) {
return token.replace("Bearer", "").trim();
}
}
package my.study.springecommercestudy.controller;
import my.study.springecommercestudy.config.jwt.JwtAuthorization;
import my.study.springecommercestudy.domain.Member;
import my.study.springecommercestudy.dto.JoinRequest;
import my.study.springecommercestudy.dto.LoginRequest;
import my.study.springecommercestudy.dto.MyProfileResponse;
import my.study.springecommercestudy.service.MemberService;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import java.net.URI;
@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));
}
@GetMapping("my-profile")
public ResponseEntity<MyProfileResponse> getMyProfile(@JwtAuthorization Member member) {
return ResponseEntity.ok(MyProfileResponse.of(member));
}
}
반응형
'프로그래밍 > Java & Spring' 카테고리의 다른 글
Spring Boot를 사용하여 JWT 기반 인증 기능을 구현하는 방법 (1) | 2024.08.21 |
---|---|
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 |
댓글