KUIT-앱 개발 프로젝트 동아리

9주차 실습(3)- 헤더에 토큰 넣기

농농씨 2023. 11. 26. 02:08

유저 정보를 가져올 때 정보를 header에 넣어줘야 한다.

헤더에 토큰을 어떻게 넣는지에 대해 알아보자

 

1. ApplicationClass 수정

1-1. access token 

companion object에 다음과 같이 Access token 에 관한 변수를 추가해준다.

const val X_ACCESS_TOKEN: String = "x-access-token"

 

1-2. client(통신에 관여하는 객체)

Retrofit 라이브러리는 OkHttp 라는 라이브러리를 기반으로 만들어지고 동작한다.

client는 원래 OkHttp에서 사용되는 객체인데, 일단은 header에 토큰을 넣을때 사용한다는 정도로만 알아두자.

 

OkHttpClient에 대한 client도 다음과 같이 추가해준다.

val client: OkHttpClient = OkHttpClient.Builder()
    .readTimeout(30000, TimeUnit.MILLISECONDS)
    .connectTimeout(30000, TimeUnit.MILLISECONDS)
    .addNetworkInterceptor(XAccessTokenInterceptor())
    .build()

 

그다음 그걸 retrofit 객체 안에 client로 넣어준다.

retrofit = Retrofit.Builder()
    .baseUrl(BASE_URL)
    .client(client) // 추가된 구문
    .addConverterFactory(GsonConverterFactory.create())
    .build()

 

.addNetworkInterceptor(XAccessTokenInterceptor()) // JWT 자동 헤더 전송

client의 이 부분은 retrofit에 네트워크 요청을 넣기 전에 client가 요청을 가로챈다는 뜻이다.

가로챈 요청을 어떻게 할 것인지에 대해서는 XAccessTokenInterceptor.kt 파일을 만들어서 작성할 것이다.

 

2. XAccessTokenInterceptor.kt

우선 클래스 파일을 만들고 다음과 같이 코드를 작성해준다.

// XAccessTokenInterceptor.kt 클래스 코드
package com.example.carrotmarket.remote

import com.example.carrotmarket.ApplicationClass.Companion.X_ACCESS_TOKEN
import okhttp3.Interceptor
import okhttp3.Request
import okhttp3.Response

class XAccessTokenInterceptor: Interceptor {
    override fun intercept(chain: Interceptor.Chain): Response {
        val builder: Request.Builder = chain.request().newBuilder()

        val jwtToken: String? = getJwt()

        jwtToken?.let {
            builder.addHeader(X_ACCESS_TOKEN, "Bearer $jwtToken")
        }
    }
}

-okhttp의 Interceptor를 상속받고 있다.

-요청을 가로채서 builder를 만든다.

retrofit의 builder의 client에 이 client를 넣어줬기 때문에 모든 요청이 갈때마다 가로채져서 여기에 들어간다.

builder.addHeader 구문으로 jwt 토큰을 헤더에 붙여주는 역할을 한다.

 

요약하자면 client가 하는 일은

local DB에 저장되어 있는 jwt 토큰을, 실제 네트워크 통신이 가기 전에 헤더에 심는 역할을 하는 것이다.

 

이때, "Bearer $jwtToken" 형식을 꼭 지켜야 한다. 서버에서 jwtToken을 디코딩하는 방식이 Bearer 라서 제약이 있다.

 

getJwt()로 Jwt 토큰을 가져오는건 미션이다

 

<실습미션>

-로그인 구현(로그인성공하면 뒤로 가지게, 닉네임 변경, 로그인버튼->로그아웃 버튼 등)

    -성공시 sharedPreferences에 jwt토큰과 닉네임 저장(나갔다 들어와도 로그인 유지되도록)

-로그아웃 구현

    -sharedPreferences 에서 jwt 토큰 삭제

 

* sharedPreference도 application class 에 등록해서 전역변수로 관리하는 게 좋다.

예시)

// application class 전체코드
package com.example.carrotmarket

import android.app.Application
import android.content.Context
import android.content.SharedPreferences
import android.util.Log
import com.example.carrotmarket.remote.XAccessTokenInterceptor
import okhttp3.OkHttpClient
import okhttp3.OkHttpClient.*
import retrofit2.Retrofit
//import retrofit2.Retrofit.Builder
import retrofit2.converter.gson.GsonConverterFactory
import java.util.concurrent.TimeUnit

class ApplicationClass : Application() {
    companion object{
        const val X_ACCESS_TOKEN: String = "x-access-token"
        const val DEV_URL : String = "http://13.125.254.172:23899"
        const val PROD_URL : String = "http://kuit_prod_url"

        const val BASE_URL : String = DEV_URL

        lateinit var retrofit : Retrofit
        lateinit var mSharedPreferences : SharedPreferences // 추가된 줄
    }

    val client: OkHttpClient = OkHttpClient.Builder()
        .readTimeout(30000, TimeUnit.MILLISECONDS)
        .connectTimeout(30000, TimeUnit.MILLISECONDS)
        .addNetworkInterceptor(XAccessTokenInterceptor()) // JWT 자동 헤더 전송
        .build()

    override fun onCreate() {
        super.onCreate()

        retrofit = Retrofit.Builder()
            .baseUrl(BASE_URL)
            .client(client)
            .addConverterFactory(GsonConverterFactory.create())
            .build()
        Log.d("Application Class", "retrofit Builder 생성")
        
        mSharedPreferences = applicationContext.getSharedPreferences("My App Spf", Context.MODE_PRIVATE)
        // 추가된 줄
    }
}

그리고 다음과같이 sharedPreference를 관리하는 파일을 만들어준다ㅏ.

코드는 다음과 같이 작성

// SharedPreferenceManager.kt
package com.example.carrotmarket.remote

import com.example.carrotmarket.ApplicationClass

fun getJwt() : String { // get 이니까 String으로 받아야 함
    // jwt 토큰 가져오는 로직 구현
}

fun removeJwt(){
    // 로그아웃 하면서 spf에서 jwt 토큰 지우는 로직 구현
}

fun saveJwt(){
    ApplicationClass.mSharedPreferences.edit().putString()
}

 

 

찜하기 기능도 spf로 구현해보는게 도전과제이다.