jwt:로그인

2023-03-18 hit count image

토큰 기반 인증 시스템인 jwt(Json Web Token)을 이용하여 로그인 절차를 구현해 봅니다.

개요

jwt 인증 시스템을 통해 로그인 절차를 구현해 보려고합니다. 이 블로그는 시리즈로 구성되어 있습니다. jwt 구현을 위한 미들웨어(Middleware) 설치나 회원가입 구현에 관해서는 이전 블로그를 참고해주세요.

저장소(Repository)

우리는 jwt 인증 시스템을 구현한 저장소(Repository)를 만들었습니다. 아래에 링크를 클릭해서 저장소(Repository)를 확인해 보세요.

개발 환경 구성

여기서 설명할 내용은 라라독(Laradock)과 앤서블(Ansible)을 이용하여 만든 라라벨(Laravel) 개발 환경에서 작업합니다. 라라독(Laradock)과 앤서블(Ansible)을 이용한 라라벨(Laravel) 개발 환경에 관해서는 아래에 블로그를 참고하세요.

모델 수정

jwt 인증 시스템의 인증에 사용되는 모델(Model)을 아래와 같이 수정합니다.

<?php
...
use Illuminate\Foundation\Auth\User as Authenticatable;
use Tymon\JWTAuth\Contracts\JWTSubject;
...
class User extends Authenticatable implements JWTSubject
{
    ...
    public function getJWTIdentifier() {
        return $this->getKey();
    }

    public function getJWTCustomClaims() {
        return [];
    }
}

라라벨(Laravle)의 인증 기능을 사용하기 위해 모델(Model)을 Authenticatable에서 상속받았습니다. 또한 jwt 미들웨어(Middleware)의 인터페이스를 JWTSubject를 통해 구현합니다.

public function getJWTIdentifier() {
    return $this->getKey();
}

public function getJWTCustomClaims() {
    return [];
}

위에 함수는 jwt 미들웨어(Middleware)의 인터페이스를 구현한 부분입니다.

public function getJWTIdentifier() {
    return $this->getKey();
}

이 부분은 jwt의 토큰을 습득하기 위한 함수입니다.

public function getJWTCustomClaims() {
    return [];
}

이 함수를 설명하기 위해 jwt 토큰을 잠시 설명하겠습니다. jwt는 크게 헤더(header).내용(payload).서명(signature)으로 구성되어 있습니다. 그중 내용(Payload)에 사용될 정보의 일부를 Claim이라고 하며, key-value 형식으로 구성되어있습니다. jwt는 기본적으로 내용(Payload)에 아래와 같은 정보(Claim)를 가지고 있습니다.

  • iss(Issuer): 토큰 발급자
  • sub(Subject): 토큰 제목(기본값은 user id)
  • iat(Issued At): 토큰 발행일(unix timestamp)
  • exp(Expiry): 토큰의 만료시간
  • nbf(Not Before): 토큰을 사용할 수 있는 시작 시간
  • jti(JWT Id): JWT의 고유 식별자. 주로 중복적인 처리를 방지하기 위하여 사용.
  • prv: 사용자 공급자 클래스(User Provider class)의 해쉬값. 다중 guard를 사용하기 위해 tymondesigns/jwt-auth에 추가한 특별한 코드.(자세한 설명)

이 정보 이외에 추가적으로 jwt토큰에 정보를 추가하고 싶다면 getJWTCustomClaims() 함수에 반환값(Return value)을 수정하면 됩니다.

public function getJWTCustomClaims() {
    return [
        'firstname' => $this->firstname,
        'lastname' => $this->lastname,
        'email' => $this->email
    ];
}

guard 수정

라라벨(Laravel)의 인증을 담당하고 있는 config/auth.php 파일의 guard를 아래와 같이 수정합니다.

'guards' => [
    'web' => [
        'driver' => 'session',
        'provider' => 'users',
    ],

    'api' => [
        'driver' => 'jwt',
        'provider' => 'users',
    ],
],

컨트롤러 수정

이전 블로그에서 생성한 app/Http/Controllers/JWTAuthController.php 컨트롤러에 로그인 함수를 추가합니다

public function login(Request $request) {
    $validator = Validator::make($request->all(), [
        'email' => 'required|email|max:255',
        'password' => 'required|string|min:8|max:255',
    ]);

    if($validator->fails()) {
        return response()->json([
            'status' => 'error',
            'messages' => $validator->messages()
        ], 200);
    }

    if (! $token = Auth::guard('api')->attempt(['email' => $request->email, 'password' => $request->password])) {
        return response()->json(['error' => 'Unauthorized'], 401);
    }

    return $this->respondWithToken($token);
}

protected function respondWithToken($token) {
    return response()->json([
        'access_token' => $token,
        'token_type' => 'bearer',
        'expires_in' => Auth::guard('api')->factory()->getTTL() * 60
    ]);
}

우선 요청(Request)의 입력 데이터를 확인합니다.

$validator = Validator::make($request->all(), [
    'email' => 'required|email|max:255',
    'password' => 'required|string|min:8|max:255',
]);

if($validator->fails()) {
    return response()->json([
        'status' => 'error',
        'messages' => $validator->messages()
    ], 200);
}

그리고 사용자의 emailpassword로 로그인 시킵니다.

if (! $token = Auth::guard('api')->attempt(['email' => $request->email, 'password' => $request->password])) {
    return response()->json(['error' => 'Unauthorized'], 401);
}

로그인에 성공하면 요청(Request)에 대한 jwt 토큰을 반환(Response)합니다.

return response()->json([
    'access_token' => $token,
    'token_type' => 'bearer',
    'expires_in' => Auth::guard('api')->factory()->getTTL() * 60
]);

라우트 연결

컨트롤러(Controller)에서 생성한 로그인 함수를 routes/api.php에서 URL과 연결합니다.

Route::post('login', 'JWTAuthController@login')->name('api.jwt.login');

테스트

이제 지금까지 만든 jwt 인증 시스템의 로그인 기능을 Postman을 통해 확인합니다. localhost/api/login URL에 emailpassword를 입력하고 POST로 요청(Request)을 보내면 아래와 같은 결과를 확인할 수 있습니다.

postman login api test

응답(Response)으로 받은 access_token키를 https://jwt.io/에서 확인해보면 아래와 같은 결과를 얻을 수 있습니다.

check access_key

완료

이것으로 jwt 인증 시스템을 이용하여 로그인 기능을 구현해보았습니다. 다음 블로그에서는 access token을 이용한 사용자 정보를 얻는 방법에 대해서 알아보도록 하겠습니다.

참고

제 블로그가 도움이 되셨나요? 하단의 댓글을 달아주시면 저에게 큰 힘이 됩니다!

앱 홍보

책 홍보

블로그를 운영하면서 좋은 기회가 생겨 책을 출판하게 되었습니다.

아래 링크를 통해 제가 쓴 책을 구매하실 수 있습니다.
많은 분들에게 도움이 되면 좋겠네요.

스무디 한 잔 마시며 끝내는 React Native, 비제이퍼블릭
스무디 한 잔 마시며 끝내는 리액트 + TDD, 비제이퍼블릭
[심통]현장에서 바로 써먹는 리액트 with 타입스크립트 : 리액트와 스토리북으로 배우는 컴포넌트 주도 개발, 심통
Posts