JWT (Jason Web Token)
유저 인증, 식별하기 위한 토큰 기반의 인증
구조
- 헤더 (Header)
- 타입 (type) : 항상 JWT
- 알고리즘 (alg)
- 페이로드 (Payload) : 사용자 정보 담김
- 서명 (Verify Signature)
동작 방식
1. 클라이언트측에서 부터 서버측으로 JWT 받음
2. 서버측의 비밀 값과 JWT의 헤더, 페이로드를 alg에 넣고 서명값과 같은지 확인
3. 같다면 유저에 인가
특징
- 시간에 따라 상태값이 달라지지 않음 (Stateless)
- 서버가 통제하지 않아 여러 사용자가 같은 JWT로 여러 요청 보내도 추적 불가능
종류
- Access Token : 인가받을 때 쓰는 수명이 짧은 토큰
- Refresh Token : Access Token을 재발급 받을 때 쓰는 수명이 긴 토큰 (DB에 저장, 관리)
OAuth
사용자들이 특정 사이트에 직접 회원가입 및 비밀번호를 제공하지 않고 접근하기 위해 권한을 부여받는 수단으로 사용되는 방식
👍 회원 관리 기능 (회원가입, 로그인, 비밀번호 찾기 등) 구현 시 신경 써야 할 부분들을 대신 해줘 개발, 관리 편함
- 인증 Authentication: 해당 사용자가 본인이 맞는지 판단 (사용자 신원 확인)
- 인가 Authorization: 인증된 사용자가 요청한 자원에 권한 있는지 판단 (사용자 권한 위임)
OAuth 1.0
- 역할
- Resource Owner
- OAuth Client
- OAuth Server
- 흐름
- 1. client에서 server로 요청
- 2. 인증, 인가 처리
- 3. client에서 resource owner에게 전달 (인증)
- 4. server에서 resource owner 확인 받음 (인가)
- 5. server에서 client로 접근 = JWT 발급
- 문제점
- Scope 개념 없음 (Scope : 유저 토큰(JWT)을 통해 데이터를 얻어오는 범위)
- 토큰의 유효 기간 문제
- 역할이 정확히 나눠져있지 않음
- client 구현 복잡
- 제한적인 웹 환경 (정적 리소스)
OAuth 2.0
- 바뀐점
- Scope 기능 추가 : 해당 토큰에 대한 접근 제한 범위 설정
- client 구현 복잡성 간소화
- Bearer Token + TLS
- 토큰 탈취 문제 개선
- Access Token + Refresh Token
- 동적 리소스 웹 환경까지 확장
Spring Security
https://docs.spring.io/spring-security/reference/index.html
스프링에서 필터를 사용해 유저 인증 / 인가 등 보안 기능을 쉽게 하도록 제공하는 프레임워크
👍 모든 요청이 인증되어야 자원에 접근 가능해짐 (메소드 단위 권한 부여)
주요 제공 기능
- 애플리케이션과의 모든 상호작용을 위해 인증된 유저 요청
- 기본 로그인 폼 제공
- BCrypt로 저장된 비밀번호 보호
- CSRF 공격 방지
구조
- FilterChain
: Servlet 컨테이너가 관리하는 ApplicationFilterChain (=/= SecurityFilterChain)
1. 클라이언트가 애플리케이션에 요청을 보냄
2. 컨테이너는 Filter 인스턴스와 Servlet(요청 URI 기반의 HttpServletRequest를 진행)를 포함한 FilterChain 생성
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {
// do something before the rest of the application
chain.doFilter(request, response);
// invoke the rest of the application
// do something after the rest of the application
}
- DelegatingFilterProxy
: Servlet 컨테이너의 라이프사이클과 스프링 ApplicationContext 사이의 연결을 허용하는 필터 구현체
(= Servlet 컨테이너와 Spring IOC 컨테이너 사이의 연결해주는 역할)
- FilterChainProxy
: SecurityFilterChain을 통해 많은 필터 인스턴스를 위임하게 해주는 특별한 필터
- SecurityFilterChain
: FIlterChainProxy에 의해 스프링 시큐리티 필터 인스턴스가 현재 요청을 호출하도록 함
SecurityFilterChain 여러개 사용하는 경우
요청 처리 구성 요소
HTTP 요청이 서버에 들어오면 DelegatingFilterProxy를 통해 Spring Security Filter Chain이 생성된다.
이는 요청 단위의 보안을 제공하는데 이 작업의 요청이 어떻게 처리되어야 하는지 결정된다.
모든 필터를 통과하면 각 요청은 등록된 Controller로 도달한다.
이후 서비스단으로 가기 전에 스프링 시큐리티는 AOP를 통해 메소드 단위로 권한 부여를 수행한다.
핵심 개념
- Authentication : 인증된 사용자 객체 (현재 로그인된 사용자)
- GrantedAuthority : 사용자에게 부여된 권한
- SecurityContext : Authentication 객체를 캡슐화하는 인스턴스
- SecurityContextHolder : 권한 부여를 수행할 때 사용
Maven
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
Gradle
dependencies {
compileOnly "org.springframework.boot:spring-boot-starter-security"
}
의존성 추가 후 서버를 실행하면 이렇게 자동으로 security password가 생성된다.
그리고 기본 포트로 접속하면 로그인 창이 뜬다. 이는 스프링 시큐리티로 인해 그 어떤 요청을 하든 인증을 해야 접근할 수 있게 된 것이다.
아이디는 아무거나, 비밀번호는 생성된 대로 적어 sign in을 해줘야 내가 설정한 대로 요청-응답이 된다.
application.properties에서 내가 직접 스프링 시큐리티 이름과 비밀번호를 설정해줄 수도 있다.
spring:
security:
user:
name: user
password: 1234
세션
인증된 사용자에게 스프링 시큐리티는 세션 ID를 발급하고 이를 통해 관리한다.
앞서 로그인한 사용자의 세션을 개발자도구로 확인할 수 있다.
스프링 시큐리티 설정
: WebSecurityConfigurerAdapter 상속해 커스텀 설정
👍 커스텀된 FilterChainProxy가 추가 되는 것
OAuth 로그인 관련 설정도 여기서 해준다.
참고
실전! 스프링 5와 Vue.js 2로 시작하는 모던 웹 애플리케이션 개발 | 제임스 J. 예 - 교보문고 (kyobobook.co.kr)
댓글