닷넷 6.0에서의 JWT 인증

해질녘·2022년 2월 8일
0

닷넷 (.NET)

목록 보기
4/12

.NET 6.0 - JWT Authentication

.NET 6.0 - JWT Authentication Tutorial with Example API | Jason Watmore's Blog

위 튜토리얼의 발췌 번역입니다. 공부하려고 보면서 한국어로 옮겼습니다.


예시 API는 2가지 endpoint/route가 있다. JWT 검증과 JWT에 제한된 경로로 접근하는 endpoint.

  • /users/authenticate

    • HTTP POST request를 받아들이는 퍼블릭 route.

    • body에 username과 password 포함.

    • 옳은 유저네임, 패스워드라면 유저 세부사항과 JWT authentication 토큰을 반환함.

  • /users

    • HTTP GET request를 받는 secure route.

    • 어플리케이션의 모든 유저 리턴. 단, HTTP의 Authorization 헤더가 유효한 JWT 토큰을 가진 경우에만. 유효한 토큰이 아니거나 토큰이 없으면 401 (Unauthorized) 오류.

.NET 6.0 JWT Authentication API 프로젝트 구조

아래 폴더

  • Controllers

    • 웹 api의 end point/route를 정의한다. 컨트롤러는 클라이언트 어플리케이션이 http request를 통해 web api로 진입하는 entry point이다.
  • Models

    • 컨트롤러 메소드에 대해 request, response model을 나타낸다.

    • 들어오는 request에 대해 parameter를 정의하는 request model

    • 어떤 데이터가 반환되는지에 대해 정의하는 response model

  • Services

    • 비즈니스 로직, validation, data access code
  • Entities

    • 어플리케이션 데이터를 나타냄
  • Helpers

    • 나머지 위 폴더에 해당하지 않는 것들

.NET JWT Users Controller

Path: /Controllers/UsersController.cs

유저와 관련된 routes/endpoints 정의한다. 이것은 authentication과 표준 CRUD operation을 포함한다. 각 루트에서 컨트롤러는 user service 를 호출한다. 호출해서 컨트롤러가 lean닿는데(?) 필요한 액션을 하고 비즈니스 로직과 데이터 액세스 코드와 완전히 분리하게 해준다.

 [Authorize] 속성이 붙은 루트는 authenticated된 유저만 접근 가능하도록 제한된다. 인증 로직은 /Helpers/AuthorizeAttribute.cs에 나타남.

.NET JWT User Entity

Path: /Entities/User.cs

유저 entity는 어플리케이션에서 유저 데이터를 나타낸다. 어플리케이션의 서로 다른 부분(예: 서비스와 컨트롤러 사이)에서 데이터를 전달할때 쓰인다. 컨트롤러 액션 메소드에서 http response 데이터를 반환하는데에도 쓰인다. 만약 여러 종류의 엔티티나 커스텀 데이터가 컨트롤러 메소드에서 반환되기 위해 필요하다면, response를 위해 Models 폴더에 커스텀 모델 클래스를 생성해야 한다.

[JsonIgnore] 속성은 비밀번호 property가 직렬화 되거나 api response로 반환되지 않도록 방지해준다.

.NET JWT App Settings

Path: /Helpers/AppSettings.cs

앱세팅 클래스는 appsettings.json파일에 정의된 property들을 가지고 있다. 앱세팅 클래스는 닷넷 빌트인 DI (의존성 주입) 시스템에서 주입하는 오브젝트에 세팅하는 걸 접근할 때에도 쓰인다. 예를 들어서, user service는 앱세팅에 접근할 때 IOptions<AppSettings> appSettings 오브젝트를 경유한다. 이 오브젝트는 생성자를 통해 주입된다.

configuration section을 클래스로 매핑하는 과정은 Program.cs에서 완료된다.

.NET Custom Authorize Attribute

Path: /Helpers/AuthorizeAttribute.cs

커스텀 authorize (인증) attribute(속성)은 유저가 인증되어야 하는 상황의 컨트롤러 액션 메소드에 더해진다.

인증은 OnAuthorization 메소드를 통해 수행된다. 이 메소드는 현재 request (context.HttpContext.Items["User"])에 인증된 유저가 attached 됐는지 체크한다. 인증된 유저는 request가 유효한 JWT 액세스 토큰을 가지고 있는 경우에, custom jwt middleware를 통해 attach 된다.

컨트롤러 액션 메소드에 전달되는 것: 인증 성공 시 no action. 인증 실패 시 401 Unauthorized response.

.NET Custom JWT Middleware

Path: /Helpers/JwtMiddleware.cs

커스텀 JWT 미들웨어는 request Authorization 헤더에 토큰이 있는지 확인한다. 있다면 다음을 시도

  1. 토큰 유효성 검증

  2. 토큰으로부터 user id 추출

  3. 현재 HttpContext.Items collection에 인증된 유저를 부착attach한다. 그러면 현재 request의 범위에 접근가능하게 된다.

request 헤더에 토큰이 없거나, 위 3단계 중 하나라도 실패하면, http context에는 user가 attach되지 않는다. 그리고 해당 request는 public route만 접근가능하게 된다. 인증은 custom authorize attribute를 통해 수행된다. 그것은 유저가 http context에 부착되어있는지 확인하고, 인증 실패 시 401 Unauthorized response를 반환한다.

.NET JWT Authenticate Request Model

Path: /Models/AuthenticateRequest.cs

인증 리퀘스트 모델은 /users/autheticate 루트로 들어오는 reauest에 대해 파라미터를 정의한다. 인증 리퀘스트 모델은 users controller의 Authenticate 액션 메소드의 파라미터로서 route에 부착되어있다. HTTP POST request가 루트를 통해 수신되면, body의 데이터는 AuthenticateRequest 클래스의 인스턴스로 채워진다. 그리고 검증하고 메소드로 전달됨.

모델 검증을 자동으로 하기 위해 .NET의 데이터 annotation이 쓰인다. [Required] 이런 속성이 유저네임과 비밀번호를 요구되는 field에 set 해준다. 거기에 인증 오류 메시지가 있는지 체크. (해석애매함 .NET Data Annotations are used to automatically handle model validation, the [Required] attribute sets both the username and password as required fields so if either are missing a validation error message is returned from the api.)

.NET JWT Authenticate Response Model

Path: /Models/AuthenticateResponse.cs

인증 response 모델은 인증 성공 후에 반환될 데이터를 정의한다. 그것은 기본적인 유저 detail과 JWT access token을 포함한다.

.NET JWT User Service

Path: /Services/UserService.cs

유저서비스는 유저 credential을 인증하고 JWT 토큰을 반환하는 메소드를 포함하고 있다. 이는 어플리케이션의 모든 유저 가져오기, 한명의 user를 id로 찾기 등 가능.

유저 array 예시 코드는 튜토리얼 제작자가 임의로 하드코딩한 것. 프로덕션 어플리케이션에서는 데이터베이스에 해싱된 패스워드를 저장하는 것을 권장한다. 더 나아간 예시가 궁금하다면 .NET 5.0 - Simple API for Authentication, Registration and User Management 이쪽을 체크! 유저 회원가입과 엔티티 프레임워크로 데이터 저장하는 법. (와 저에게 딱 필요해요~)

파일의 제일 위에는 user service 정의하는 인터페이스 포함. 아래에는 해당 인터페이스를 구현하는 실제 user service class 포함.

인증 성공 시, Authenticate() 메소드가 JWT 토큰을 생성한다. 셍성할 때 JwtSecurityTokenHandler 이용한다. 이 핸들러는 appsettings.json에 저장되어있는 비밀 키를 이용해 서명된 토큰을 만든다. JWT 토큰은 비밀 경로의 subsequent 헤더의 HTTP 인증 헤더에 포함되어있는 경우에만, 클라이언트 어플리케이션으로 반환된다.

.NET JWT App Settings

Path: /appsettings.json

최상단root의 configuration file이다. 어플리케이션의 모든 환경 설정을 포함한다.

중요! "Secret"이라는 속성은 api가 인증을 위해 JWT 토큰을 sign하고 검증하는데에 스인다. 그것은 유저의 random string으로 변경하여 이용한다.

OmniSharp Config

Path: /omnisharp.json

이 파일은 VS Code에서 C# 확장기능을 사용하는데에 필요한 configuration option이다. useBundleOnly 옵션은 C# 확장기능에게 전역 버전 대신 번들된 MSBuild 버전을 이용하도록 한다. 이렇게 하면 오래된 전역 MSBuild 버전 (예: VSC에 설치되어 있는) 을 사용하는 오류를 막는다.

.NET JWT Program

Path: /Program.cs

닷넷6 프로그램은 씨샵 10버전의 top-level statement를 가지고 있음. 보통 program.cs 파일에 있다. Main() 메소드.

WebApplication 클래스는 어플의 시작, 수명 관리, 웹서버 configuration 등등 관리한다. WebApplicationBuilder는 정적 함수WebApplication.CreateBuilder(args) 를 호출하는 걸로 시작. 그 빌더는 DI configure. 웹어플리케이션의 인스턴스는 builder.Build() 호출하여 생성된다. 그 인스턴스는 HTTP request pipeline(middleware) configure 하는데에 쓰인다. 어플은 app.Run()을 통해 구동.

.NET JWT Web Api csproj

Path: /WebApi.csproj

씨샵 프로젝트의 MSBuild based file. 타깃 프레임워크와 NuGet 패키지 의존성 주입 정보 가지고 있다.

ImplicitUsings 피쳐는 컴파일러에게 프로젝트 유형에 따른 a set of global using directives를 자동 생성하게 한다. 그리고 겹치는 using 선언문을 쓸 필요가 없게 한다.

글로벌 using statement는 프로젝트 빌드 시 자동으로 만들어진다. /obj/Debug/net6.0/WebApi.GlobalUsings.g.cs 경로에 존재한다.

profile
해질녘 | 백엔드 공부 중

0개의 댓글