Spring Boot - Jwt (2) 파일 구조, gradle

ysh·2023년 11월 27일
0

인턴십

목록 보기
23/25

Spring Initializr

파일 구조

  • java 파일들은 솔직히 위치는 상관없을 듯 하고 파일 구조도 개인 마다 다르니 참고로만,
    이름들도 딱히 상관 없을 듯 하다. 나중에 클래스 선언 때 맞춰서 쓰기만 하면 되니

  • 참고로 패키지 명에 .이 들어간 건 두 단계이다 ex)model.member -> model 패키지 안에 member 패키지

  • JwtAuthorizationFilter.java
    : Jwt를 검증하고 SecurityContextHolder에 유저 인증 정보를 넣어줄 필터. 직접 만들어서 적용할 예정

  • JwtProvider.java (생성, 검증)
    : Jwt를 생성한다.
    : JwtAuthorizationFilter에서 이 객체의 verify 함수를 호출하여 검증한다.

  • JwtToken.java
    : AccessToken과 RefreshToken을 함께 반환하기 위한 객체

  • JwtTokenType.java
    : 토큰의 타입을 정해놓은 Enum.

  • CustomUserByIdxService.java
    : Jwt에 담긴 유저의 Idx로 유저 정보를 불러와 CustomUserDetails 객체를 생성할 서비스.

  • CustomUserDetails.java
    : 유저의 인증 정보가 담길 객체.

  • ResDTO.java
    : 응답 형식을 구조화 해놓음.

  • CommonExceptionHandler.java
    : 에러 핸들러.

  • BadRequestException, UnauthorziedException.java
    : 각 에러를 편히 처리하기 위한 클래스

  • PasswordConfig.java
    : PasswordEncoder를 등록함.

  • SecurityConfig.java
    : 시큐리티 설정(내용이 너무 많다)

  • AuthController.java
    : 로그인, 회원가입 화면을 매핑해 줄 컨트롤러

  • AuthControllerApiV1.java
    : 로그인, 재로그인, 회원가입 요청을 매핑할 Rest 컨트롤러.

  • ReqLoginApiV1DTO, ReqReLoginApiV1DTO, ReqSignUpApiV1DTO.java
    각각 로그인, 재로그인, 회원가입 요청 시 받을 데이터를 담은 DTO

  • AuthServiceApiV1DTO.java
    : 실제 로그인, 재로그인, 회원가입 로직을 구현할 곳.

  • TempControllerApiV1.java
    : Jwt을 이용하여 실제로 인증이 되는 지 테스트 해 볼 API를 매핑.

  • MemberEntity, MemberRepository.java
    : 유저 정보 Entity, Repository

  • index.html
    : 메인 페이지. 로그인 화면과 회원가입 화면으로의 이동과 jwt 요청 테스트를 실행할 곳.

  • login, sign-up.html
    : 각 로그인, 회원가입을 진행할 화면.


Common

응답 형식이나, Exception을 처리하기 위한 핸들러가 담겨있다.

  • ResDTO.java - 응답 형식 구조화
package com.example.jwtvelog.common.dto;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Getter
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class ResDTO<T> {
    // 응답 코드
    private Integer code;
    // 응답 메시지
    private String message;
    // 응답 데이터
    private T data;
}
  • BadRequestException.java - 잘못된 요청 시 던질 Exception
package com.example.jwtvelog.common.exception;

public class BadRequestException extends RuntimeException {

    public BadRequestException(String message) {
        super(message);
    }

}
  • UnauthorizedException.java - 인증 Exception
package com.example.jwtvelog.common.exception;

public class UnauthorizedException  extends RuntimeException{

    public UnauthorizedException(String message) {
        super(message);
    }
}
  • CommonExceptionHandler.java - 위 Exception들의 핸들러
package com.example.jwtvelog.common.exception.handler;

import com.example.jwtvelog.common.dto.ResDTO;
import com.example.jwtvelog.common.exception.BadRequestException;
import com.example.jwtvelog.common.exception.UnauthorizedException;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

@RestControllerAdvice
public class CommonExceptionHandler {

        @ExceptionHandler(BadRequestException.class)
        public HttpEntity<?> handleBadRequestException(BadRequestException e) {
                return new ResponseEntity<>(
                                ResDTO.builder()
                                                .code(-1)
                                                .message(e.getMessage())
                                                .build(),
                                HttpStatus.BAD_REQUEST);
        }

        @ExceptionHandler(UnauthorizedException.class)
        public HttpEntity<?> handleUnauthorizedException(UnauthorizedException e) {
                return new ResponseEntity<>(
                        ResDTO.builder()
                                .code(-2)
                                .message(e.getMessage())
                                .build(),
                        HttpStatus.UNAUTHORIZED);
        }
}

build.gradle

plugins {
	id 'java'
	id 'org.springframework.boot' version '3.1.6'
	id 'io.spring.dependency-management' version '1.1.4'
}

group = 'com.example'
version = '0.0.1-SNAPSHOT'

java {
	sourceCompatibility = '17'
}

configurations {
	compileOnly {
		extendsFrom annotationProcessor
	}
}

repositories {
	mavenCentral()
}

dependencies {
	// jwt 추가
	implementation group: 'com.auth0', name: 'java-jwt', version: '4.3.0'
	// validation 추가
	implementation 'org.springframework.boot:spring-boot-starter-validation'

	implementation 'org.springframework.boot:spring-boot-starter-security'
	implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
	implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
	implementation 'org.springframework.boot:spring-boot-starter-web'
	compileOnly 'org.projectlombok:lombok'
	developmentOnly 'org.springframework.boot:spring-boot-devtools'
	runtimeOnly 'com.h2database:h2'
	annotationProcessor 'org.springframework.boot:spring-boot-configuration-processor'
	annotationProcessor 'org.projectlombok:lombok'
	testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

tasks.named('bootBuildImage') {
	builder = 'paketobuildpacks/builder-jammy-base:latest'
}

tasks.named('test') {
	useJUnitPlatform()
}

yml

spring:
  thymeleaf:
    cache: false
  datasource:
    url: jdbc:h2:mem:testdb;MODE=MySQL;DB_CLOSE_DELAY=-1
    driverClassName: org.h2.Driver
    username: sa
    password:
  h2:
    console:
      enabled: true
      path: /h2
  sql:
    init:
      encoding: UTF-8
      # schema-locations: classpath:h2/schema.sql
      # dataLocations: classpath:h2/data.sql
      mode: always
  jpa:
    defer-datasource-initialization: true
    open-in-view: false # 트랜잭션 범위 밖에서 영속성 컨텍스트를 유지할지 여부
    database-platform: org.hibernate.dialect.H2Dialect
    hibernate:
      ddl-auto: create # create-drop, update, validate, none
      naming:
        physical-strategy: org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
        implicit-strategy: org.hibernate.boot.model.naming.ImplicitNamingStrategyLegacyJpaImpl
    show-sql: true
    properties:
      hibernate:
        format-sql: true
        use-sql-comments: true
        default-batch-fetch-size: 500
  servlet:
    multipart:
      max-request-size: 300MB
      max-file-size: 300MB

secret key를 yml로 빼야될 것 같기도 하다.
현재 서명에 쓰이는 secert key를 JwtProvider에 직접 정의하고 있다.

  • secret key는 openssl로 랜덤 문자열을 생성해서 사용했다.

    윈도우에는 기본적으로 깔려있지 않아서 git bash에서 실행했다.
profile
유승한

0개의 댓글

관련 채용 정보