본문 바로가기
프로그래밍/Java & Spring

SpringBoot Jwt토큰 유효성검사, member 정보를 받아서 처리하는 기능 구현

by 방구석개발자 2024. 10. 7.
반응형

 

지난 포스팅에서는 jwt인증기능을 구현해봤습니다.(https://roomconerdeveloper.tistory.com/184)

 

이번엔 jwt토큰 유효성검사, member정보를 받아오는api를 구현해 보겠습니다.

 

소스코드는 github에 있습니다.

https://github.com/lsm7179/spring-eCommerce-study/tree/step2

 

GitHub - lsm7179/spring-eCommerce-study

Contribute to lsm7179/spring-eCommerce-study development by creating an account on GitHub.

github.com

 

로그인 한 유저가 내정보를 가져오는 간단한 시퀀스 다이어 그램입니다.

 

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));
    }

}
반응형

댓글