- 인증 (Authentication)
사용자가 누구인지 확인하는 절차 (ex.회원가입, 로그인)- 인가 (Authorization)
사용자가 요청(Request)하는 동작을 할 수 있는 권한이 있는지 확인하는 절차 (ex.글 삭제,즐겨찾기 접근)
서버 측에서 사용자들의 정보를 기억
서버에서 사용자들의 정보를 기억하기 위해 데이터베이스 등을 통해 (세션)정보를 저장하는데,
클라이언트로부터 요청을 받으면(ex. 로그인) 세션에 사용자 정보를 저장해두고 클라이언트의 상태를 계속해서 유지해서(statefull) 이 정보를 서비스에 이용한다.
세션&토큰에 더 자세한 설명은 이전에 포스팅을 정리해두었다.
세션의 동작 방식은 다음과 같다.
사용자에게 토큰을 발급하면 클라이언트가 발급받은 토큰을 기억
인증받은 사용자들에게 토큰을 발급하면 클라이언트가 서버에 요청을 할 때 헤더에 토큰을 함께 보내도록 하여 유효성 검사를 한다.
확장성 측면
토큰은 클라이언트 측에 저장된다. 때문에 클라이언트와 서버의 연결고리가 없기 때문에, 서버는 Stateless 하여 확장하기에 매우 적합하다. 또한 토큰을 사용하면, 세션 정보가 있는 서버를 찾을 필요 없으므로 어떠한 서버로 요청이 와도 상관이 없다.
OAuth의 경우 소셜 계정(ex.Naver)을 이용하여 다른 웹서비스에서도 로그인이 가능하다.
보안성 측면
클라이언트가 서버로 요청을 보낼 때 더 이상 쿠키를 전달하지 않으므로, 쿠키 사용에 의한 취약점이 사라지게 된다.
하지만 토큰 환경의 취약점이 존재할 수 있고 만일 토큰이 공격자(해커)에게 탈취되었다면, 한번 발급된 토큰은 임의로 만료시킬 수 없으므로 공격자는 토큰이 만료될 때까지 계속 공격 할 수 있다.
토큰 인증 동작 방식은 다음과 같다.
세션 기반 인증
토큰 기반 인증
두 방식의 차이
'인증 확인 증거를 어디에 저장하는가' 이다.
세션 기반 인증은 서버(DB 서버)에, 토큰 기반 인증은 클라이언트 측에 저장한다.
데이터 요청 시 인증 정보 전달 방법은 HTTP 인증 프레임워크를 통해서 전달된다.
웹 애플리케이션이 HTTP 요청 메시지를 받으면, 서버는 요청을 처리하는 대신에 현재 사용자를 식별할 수있는 '인증 요구'로 응답할 수 있다.
HTTP는 사용자 인증을 하는 데 사용하는 자체 인증요구/응답 프레임워크를 제공한다.
추가로, 필요에 따라 고쳐 쓸 수 있는 제어 헤더를 통해, 다른 인증 프로토콜에 맞추어 확장할 수 있는 프레임워크를 제공한다.
일반적인 HTTP 인증 프레임 워크 응답 흐름은 다음과 같다.
GET /favorites HTTP/1.1
accept: application/json
HTTP/1.1 401
...
WWW-Authenticate: Bearer realm="Nextstep"
...
GET /favorites HTTP/1.1
authorization: Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ7XCJpZFwiOjEsXCJlbWFpbFwiOlwiZW1haWxAZW1haWwuY29tXCIsXCJwYXNzd29yZFwiOlwicGFzc3dvcmRcIixcImFnZVwiOjIwLFwicHJpbmNpcGFsXCI6XCJlbWFpbEBlbWFpbC5jb21cIixcImNyZWRlbnRpYWxzXCI6XCJwYXNzd29yZFwifSIsImlhdCI6MTU5NDkwNjAwMCwiZXhwIjoxNTk0OTA5NjAwfQ.wA44l_2vBJAS_oZDSW4mQ4r-Wwgao2tMCYGjW0f_nEs
accept: application/json
...
HTTP/1.1 200
...
[
{
"id": 1,
"source": {
"id": 1,
"name": "교대역",
"createdDate": "2020-07-16T22:26:39.604",
"modifiedDate": "2020-07-16T22:26:39.604"
}
}
]
- 토큰 발급
로그인
기능 인수 테스트 구현- 토큰 인증을 통한
내 정보 조회
기능 구현- 토큰 인증을 통한
즐겨 찾기
기능 구현
세션 인증 기반 인수 테스트
토큰 인증 기반 인수 테스트
RequestSpecification.auth()
HTML form 로그인
RestAssured
.given().log().all()
.auth().form(email, password, new FormAuthConfig("/login/session", NAME, PASSWORD))
.accept(MediaType.APPLICATION_JSON_VALUE).
.when().get("/members/me")
.then().log().all().
.statusCode(HttpStatus.OK.value())
.extract();
코드 구현 예제
@Test
void 내_정보_조회() {
//given
회원_생성_요청(EMAIL, PASSWORD, AGE);
String token = 로그인_되어_있음(EMAIL, PASSWORD);
//when
ExtractableResponse<Response> findResponse = 내_정보_조회_요청(token);
//then
회원_정보_조회됨(findResponse, EMAIL, AGE);
}
public static ExtractableResponse<Response> 내_정보_조회_요청(String token) {
return RestAssured
.given().log().all()
.auth().oauth2(token)
.accept(MediaType.APPLICATION_JSON_VALUE)
.when().get("/members/me")
.then().log().all()
.extract();
}
[참조]
https://mangkyu.tistory.com/55
https://velog.io/@arthur/%EC%84%B8%EC%85%98-%EC%9D%B8%EC%A6%9D-%EB%B0%A9%EC%8B%9D-vs-%ED%86%A0%ED%81%B0-%EC%9D%B8%EC%A6%9D-%EB%B0%A9%EC%8B%9D#%EC%84%B8%EC%85%98-%EA%B8%B0%EB%B0%98-%EC%9D%B8%EC%A6%9D-vs-%ED%86%A0%ED%81%B0-%EA%B8%B0%EB%B0%98-%EC%9D%B8%EC%A6%9D / 세션,토큰 기반 인증
https://runebook.dev/ko/docs/http/authentication
https://kscodebase.tistory.com/316 / HTTP authentication
프로젝트 공방 1기 - 인증과 인증 도구