인증 방식에는 크게 두 가지가 있다.
- 세션 방식 : 로그인하면 서버가 세션을 만들어서 저장하고, 클라이언트는 세션 ID를 쿠키에 담아 요청한다.
서버가 세션을 직접 저장하기 때문에 서버가 여러 대로 늘어나면 세션 공유 문제가 생긴다. - JWT 방식 : 로그인하면 서버가 토큰을 발급하고 클라이언트가 이를 저장한다. 이후 요청마다 토큰을 헤더에 담아 보내면 서버는 토큰을 검증하기만 하면 된다.
서버가 아무것도 저장하지 않아서 서버가 여러 대로 늘어나도 문제 없다.
인증 흐름
로그인 시
로그인 요청 → AuthService에서 이메일/비밀번호 검증 → 검증 성공 시 JWT 토큰 발급 → 클라이언트가 토큰 저장
이후 API 요청 시Authorization 헤더에 토큰을 담아서 요청 → JwtAuthenticationFilter가 토큰 추출 및 검증 → 유효한 토큰이면 SecurityContext에 인증 정보 저장 → API 접근 허용
지금 코드는 누구나 모든 API에 접근할 수 있다.
이 코드를 로그인한 사용자만 상품을 등록하고 조회할 수 있도록 인증을 추가해보려고 한다.
build.gradle에 의존성 추가
dependencies {
...
// Spring Security
implementation 'org.springframework.boot:spring-boot-starter-security'
// JWT
implementation 'io.jsonwebtoken:jjwt-api:0.12.3'
runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.12.3'
runtimeOnly 'io.jsonwebtoken:jjwt-jackson:0.12.3'
}
코드 수정없이 의존성 추가만 한 뒤에 Postman으로 요청을 보내면 401 응답이 온다.

build.gradle 에 Spring Security를 추가하는 것만으로 모든 API에 인증이 필요해진다.
이제 인증 설정을 구성해보자.
com.seongmo.myshop 하위에 auth 패키지를 만들고 파일들을 추가했다.
com.seongmo.myshop
├── member
├── item
├── exception
└── auth
├── AuthController.java
├── AuthService.java
├── JwtTokenProvider.java
├── JwtAuthenticationFilter.java
├── SecurityConfig.java
└── dto
├── LoginRequest.java
└── LoginResponse.java
application.yml 수정
application.yml 파일에 JWT 설정을 추가한다.
spring:
...
jwt:
secret: myshop-secret-key-must-be-at-least-32-characters-long
expiration: 86400000 # 24시간 (밀리초)
JWT 토큰을 만들고 검증할 때 서명(Signature)이 필요하다. 서명은 "해당 토큰이 우리 서버에서 만든 토큰이 맞다"라는 걸 증명하는 역할을 한다.
이 값을 위 코드처럼 application.yml에 그냥 넣어두는 것이 맞을까?
당연히 안된다. 실무에서는 다음과 같은 방법을 쓴다고 한다.
- application.yml 을 .gitignore 에 추가하고 깃에는 application.yml.example 등의 파일을 만들어서 secret 값을 비워둔 채로 올리기
- 환경변수에 JWT_SECRET 등의 값을 저장해두고 application.yml에는 secret: ${JWT_SECRET} 과 같은 방식으로 사용하기
나는 일단 공부용이니 application.yml 에 넣었다..
SecurityConfig.java
회원가입, 로그인 그리고 상품 조회는 로그인하지 않은 사용자도 볼 수 있어야 하므로 인증없이 API 요청을 할 수 있게 열어두고, 나머지 API(상품 등록, 수정, 삭제 등)는 로그인한 사용자만 접근할 수 있도록 authenticated() 로 막았다.
.authorizeHttpRequests(auth -> auth
.requestMatchers(HttpMethod.POST, "/api/members").permitAll() // 회원가입
.requestMatchers(HttpMethod.POST, "/api/auth/login").permitAll() // 로그인
.requestMatchers(HttpMethod.GET, "/api/items/**").permitAll() // 상품 조회
.anyRequest().authenticated() // 나머지는 인증 필요
)
GitHub - SeongmoAhn/myshop-project at 260331-spring-security
Contribute to SeongmoAhn/myshop-project development by creating an account on GitHub.
github.com
앞으로는 코드가 길어져서 깃허브에 태그를 만들고 링크를 첨부하는 방식으로 업로드 하려고한다.
'Backend > Spring' 카테고리의 다른 글
| [Backend/Spring] Spring Boot - Redis 연동과 캐싱 (0) | 2026.03.31 |
|---|---|
| [Backend/Spring] Spring Boot - 테스트 코드(JUnit5 / Mockito) (0) | 2026.03.31 |
| [Backend/Spring] Spring Boot - 예외 처리 (0) | 2026.03.29 |
| [Backend/Spring] Spring Boot - @OneToMany 와 N+1 문제 (0) | 2026.03.29 |
| [Backend/Spring] Spring Boot - JPA 연관관계 (0) | 2026.03.29 |