jjwt만 이용하여 로그인 구현하기

이원찬·2024년 1월 2일
0

Spring

목록 보기
7/13

jjwt에 대한 설명을 먼저 보고오자

JWT란? (jjwt 라이브러리)

JwtService 생성

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

}

MemberController에서 JWT발급과 인증 처리하기

Member

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

MemberController

@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 헤더값을 넣어야 인증된다.

만약 권한이 없거나 유효시간이 지났다면

아래와 같이 에러가 발생한다.

profile
소통과 기록이 무기(Weapon)인 개발자

0개의 댓글