토큰 기반 인증을 사용하는 이유

1. Stateless 서버

  • Stateful 서버는 클라이언트에게서 요청을 받을 때 마다, 클라이언트의 상태를 계속해서 유지하고, 이 정보를 서비스 제공에 이용한다.
  • ex) 세션을 유지하는 웹서버: 유저가 로그인을 하면, 세션에 로그인이 되었다고 저장을 해 두고, 서비스를 제공 할 때에 그 데이터를 사용한다. 세션은 서버 컴퓨터의 메모리나 데이터베이스에 저장한다.
  • Stateless 서버는 반대로, 상태를 유지 하지 않는다. 상태정보를 저장하지 않으면, 서버는 클라이언트측에서 들어오는 요청만으로만 작업을 처리한다. => 클라이언트와 서버의 연결고리가 없기 때문에 서버의 확장성 (Scalability) 이 높아진다.

2. 모바일 어플리케이션에 적합하다

모바일 어플리케이션에서 안전한 API 를 만들기 위해선 쿠키같은 인증시스템은 이상적이지 않다고 한다. (쿠키 컨테이너를 사용해야 함). 토큰 기반 인증을 도입한다면 쉽게 구현 가능

 

3. 인증정보를 다른 어플리케이션으로 전달

대표적인 예제로는, OAuth 가 있다. 소셜 계정들을 이용하여 다른 웹서비스에서도 로그인 할 수 있게 하는 것이다.

 

4. 보안

토큰 기반 인증 시스템을 사용하여 어플리케이션의 보안을 높일 수 있다. 무조건은 아니지만,,,

 

 

 

JWT란?

jwt.io/introduction/

JWT 는 . 을 구분자로 3가지의 문자열로 되어있다. 구조는 아래와 같다.

 xxxxx.yyyyy.zzzzz 

 

1. 헤더

  • typ: 토큰의 타입을 지정
  • alg: 해싱 알고리즘을 지정. 해싱 알고리즘으로는 보통 HMAC SHA256 혹은 RSA 가 사용되며, 이 알고리즘은, 토큰을 검증 할 때 사용되는 signature 부분에서 사용된다.
{
  "typ": "JWT",
  "alg": "HS256" // HMAC SHA256 이 해싱 알고리즘으로 사용
}

 

 

2. Payload

토큰에 담을 정보가 들어있다. 여기에 담는 정보의 한 ‘조각’ 을 클레임(claim) 이라고 부르고, 이는 name / value 의 한 쌍으로 이뤄져있다. 토큰에는 여러개의 클레임 들을 넣을 수 있다. 클레임은 3가지 종류가 있다.

  • Registered claims: 서비스에서 필요한 정보들이 아닌, 토큰에 대한 정보들을 담기위하여 이름이 이미 정해진 클레임들로, optional
  • Public claims: 충돌이 방지된 (collision-resistant) 이름을 가지고 있어야 한다. 충돌을 방지하기 위해서는, 클레임 이름을 URI 형식으로 짓는다.
  • Private claims: 위의 두 경우가 아닌 모든 경우를 말한다. 양 측간에 (보통 클라이언트 <->서버) 협의하에 사용되는 클레임 이름들로, 공개 클레임과는 달리 이름이 중복되어 충돌이 될 수 있으니 사용할때에 유의해야한다.

3. 서명

헤더의 인코딩값과, 정보의 인코딩값을 합친후 주어진 비밀키로 해싱을 해서 생성한다. 그 결과를 base64 형태로 나타낸다. (문자열을 인코딩 하는게 아닌 hex  base64 인코딩을 해야함)

 

 

Spring Security란?

세션-쿠키방식으로 인증, id - password 방식

  • 스프링 기반의 어플리케이션에서 보안을 위해 인증 권한 부여를 사용하여 접근을 제어하는 프레임워크
  • 커스터마이징 가능
  • filter 기반으로 동작하기 때문에 Spring MVC와 분리되어 관리 및 동작
  • 허용되지 않은 페이지에 사용자가 접근할 경우 스프링 시큐리티는 페이지 호출 전에 인증이 되어있는지를 체크하고 페이지에 접근할 수 있는 권한이 있는지 체크 -> 허용 / 차단
  • 크리덴셜 기반 인증 사용

 

 

webfirewood.tistory.com/m/115?category=694472

스프링 시큐리티는 주로 서블릿 필터와 이들로 구성된 필터체인을 사용하고 있다. 아래는 동작 플로우이다.

1. 사용자가 로그인 정보와 함께 인증 요청(Http Request)

2. AuthenticationFilter가 이 요청을 가로챕니다. 이 때 가로챈 정보를 통해 UsernamePasswordAuthenticationToken이라는 인증용 객체를 생성합니다.

3. AuthenticationManager의 구현체인 ProviderManager에게 UsernamePasswordAuthenticationToken 객체를 전달합니다.

5. 실제 데이터베이스에서 사용자 인증정보를 가져오는 UserDetailsService에 사용자 정보(아이디)를 넘겨줍니다.

6. 넘겨받은 사용자 정보를 통해 DB에서 찾은 사용자 정보인 UserDetails 객체를 만듭니다. 이 때 UserDetails 는 인증용 객체와 도메인용 객체를 분리하지 않고 인증용 객체에 상속해서 사용하기도 합니다.

7. AuthenticationProvider는 UserDetails를 넘겨받고 사용자 정보를 비교합니다.

8. 인증이 완료되면 권한 등의 사용자 정보를 담은 Authentication 객체를 반환합니다.

9. 다시 최초의 AuthenticationFilter에 Authentication 객체가 반환됩니다.

10. Authentication 객체를 SecurityContext에 저장합니다.

 

최종적으로 SecurityContextHolder는 세션 영역에 있는 SecurityContext에 Authentication 객체를 저장한다. 세션에 사용자정보를 저장한다는 것은 스프링 시큐리티가 전통적인 세션-쿠키 기반의 인증 방식을 사용한다는 것을 의미한다.

스프링 시큐리티는 기본적으로 약 10개의 스프링 시큐리티 필터가 자동으로 설정되는데, 훨씬 다양한 필터체인을 사용하여 커스터마이징을 할 수 있다.

더보기

spring security는 필터 기반으로 동작하며 spring security에서 실행되는 필터만 20개가 넘는다

<http>태그의 auto-config속성이 true로 설정이 되면 10개 정도의 필터가 체인으로 만들어져서 동작한다.

      - SecurityContextPersistenceFilter
      - LogoutFilter
      - UsernamePasswordAuthenticationFilter
      - DefaultLoginPageGeneratingFilter
      - BasicAuthenticationFilter
      - RequestCacheAwareFilter
      - SecurityContextHolderAwareRequestFilter
      - AnonymousAuthenticationFilter
      - SessionManagementFilter
      - ExceptionTranslationFilter
      - FilterSecurityInterceptor

 

 

서블릿 필터? 필터 체인?

 

필터

컨테이너에 전달된 요청이 서블릿을 호출하기 전에 이 필터를 거치게 된다.

필터에서 서블릿의 service 메소드를 호출할 때 request, response 객체를 인자로 넘겨주게 된다. (servlet의 response 객체는 OuputStreamWriter 객체를 참조하고 있고 servlet 에서는 이 객체를 통해 직접 응답을 클라이언트로 전달)

문제는 필터에서 response 객체에 접근하고 싶을 때 발생한다. service 메소드가 종료된 시점에서 이미 response 가 클라이언트로 전달 된 다음이기 때문에 필터에서는 response 객체에 접근할 수가 없다. 이 때 wrapper 클래스를 사용하여 필터에서 wrapper 클래스를 만들어 진짜 response객체 대신 래퍼객체를 보내면 된다. 그렇게 되면 servlet에서는 실제 outputstream이 아닌 래퍼의 outputstream에 응답을 작성하게 되고 필터에서 이 응답에 접근할 수 있게 된다.

 

 

 

Spring Security oauth2란?

 

 

 

 

 

 

 

 

 

 

momentjin.tistory.com/144

momentjin.tistory.com/146

 

 

'Java (+ Spring)' 카테고리의 다른 글

Mock객체로 테스트 하기: Mockito  (0) 2021.02.10
Java Unit Test: Junit5  (0) 2021.02.10
Spring boot: JPA 설정 방법 및 주의할 점  (1) 2020.07.31
Spring: Spring MVC 설정 하기  (0) 2020.07.26
Android: tutorial page  (0) 2020.07.18

+ Recent posts