소셜로그인 서버랑 연동하기

쿵ㅇ양·2024년 3월 3일
0

Android

목록 보기
19/30

여즘 하고 있는 기업프로젝트에서 소셜로그인 api연동 이슈...
마감까지 일주일 남아 매우 촉박쓰..

카카오 sdk만 연동해놓은 상황..
카카오에서 주는 Oauth2 토큰이 나와있는 상황..

로그인, 회원가입 api가 나와서 연결하기로함!!

우선!! 나는 로직부터 매우 헷갈려씀...

당연히 회원가입이 먼저라고 생각해서 회원가입 먼저 연결하고 있었는데..ㅋㅋ

로그인api가 먼저 연결이되어야 회원가입이 되어있는 회원인지 아닌지랑 서버에서 만든 액세스 토큰을 받을 수 있었던거!!
(이 사실을 회원가입api를 연결하면서 토큰이 유효하지 않는 형식이라고 400오류가
뜨는 바람에 담당서버님에게 물어봐서 알았다..ㅎㅎ)

로직

우선 카카오 sdk가 연동되어있고 카카오에서 주는 토큰이 나와있다는 가정하에..!

1. 로그인액티비티에서 로그인api 호출

카카오에서 주는 id토큰을 헤더에 담아 로그인api 호출

  • Get형식이므로 회원가입 유저 여부가 나옴
    ->true : 바로 홈화면으로 넘어가게함
    ->false: 회원가입해야하므로 온보딩으로 넘어가게함

  • 서버에서 만들어준 access토큰도 이때 나오는데 이걸 회원가입할때 헤더에 입력해 주기

2.온보딩에서 정보 다 입력하면 회원가입api 호출

온보딩에서 입력한 기업정보, 기업이름, access토큰을 intent로 데이터를 넘겨
마지막 단계에서 회원가입 api호출해서 한번에 서버로 post

⭕️ 아 글구,, 토큰 종류가 매우 많고 다 형식이 다르니 api명세서 잘 확인하자!!

⭕️ Bearer형식의 토큰을 헤더에 넣는 경우

=>Bearer ${token.idToken}으로 넣어주기

1. 로그인 코드

1. 인터페이스 작성

헤더에 Authorization 적기-> 호출할때 카카오 id토큰 넣어주기

interface LoginItf {
    @GET("주소")
    fun getLogIn(
        @Header("Authorization") idToken: String
    ): Call<getLogInResponse>

}

2. object 작성

이건 모든 api 호출할때 쓰이는!!

object RetrofitClient {

    private const val BASE_URL = "주소"


    private val retrofit: Retrofit by lazy {
        val client = OkHttpClient.Builder()
            .addInterceptor { chain ->
                val originalRequest: Request = chain.request()
                val requestWithHeaders: Request = originalRequest.newBuilder()
                    .build()
                chain.proceed(requestWithHeaders)
            }
            .build()

        Retrofit.Builder()
            .baseUrl(BASE_URL)
            .client(client)
            .addConverterFactory(GsonConverterFactory.create())
            .build()
    }

    val login: LoginItf by lazy {
        retrofit.create(LoginItf::class.java)
    }

3. 응답을 데이터 클래스로 넣어주기 위해 데이터 클래스도 만들고..

4. 이제 카카오id토큰을 헤더에 넣어서 로그인api 호출하기

여기서는 굳이 토큰을 저장해두지 않아도 되지만 저장하는 방법은 알아두면 좋음!!


//callback 카카오 로그인 결과를 처리하는 데 사용
//OAuthToken과 Throwable을 매개변수로 받아서 Unit을 반환
//토큰을 카카오에서 준 토큰을 이 함수에서 저장하고 이용
 val callback: (OAuthToken?, Throwable?) -> Unit = { token, error ->
            if (error != null) {
                // 로그인 실패
                Log.d("my log", "로그인 실패")
            }
            else if (token != null){
                // 로그인 성공
                Log.d("my log", "로그인 토큰 테스트" + token)

                // 토큰 저장
                val sharedPreferences = this.getSharedPreferences("my_token", Context.MODE_PRIVATE)
                val editor = sharedPreferences.edit()
                val gson = Gson()
                val tokenJson = gson.toJson(token)

                editor.putString("kakao_token", tokenJson)  // 카카오 토큰 전체
                editor.putString("access_token", token.accessToken) // 액세스 토큰
                editor.apply()

                RetrofitClient.login.getLogIn("Bearer ${token.idToken}").enqueue(object :
                    Callback<getLogInResponse> {
                    override fun onResponse(call: Call<getLogInResponse>, response: Response<getLogInResponse>) {
                        Log.d("토큰", token.idToken.toString())
                        if (response.isSuccessful) {
                            val logInResponse = response.body()
                            Log.d("성공",response.body().toString())
                            if (logInResponse != null) {
                                
                                //회원인경우->메인액티비티로
                                if (logInResponse.result.isUser) {
                                    val intent = Intent(this@LogInActivity, MainActivity::class.java)
                                    startActivity(intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP))
                                    finish()
                                
                           //회원이 아닌경우->온보딩(서버에서 준 access토큰과 함께)
                                } else {
                                    val intent = Intent(this@LogInActivity, OnboardingActivity::class.java)
                                    
                                    //인텐트로 access토큰도 넘겨주기                                    
                                   intent.putExtra("accessToken", logInResponse.result.accessToken)
                                    startActivity(intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP))
                                    finish()
                                }
                            }
                        } else {
                            // 회원가입 실패
                            val errorMessage = "요청 실패: ${response.code()} ${response.message()}"
                            Log.e("API 요청 실패", errorMessage)
                            // 추가 정보 출력
                            try {
                                val errorBody = response.errorBody()?.string()
                                Log.e("API 응답 에러", errorBody ?: "에러 응답 본문이 없습니다.")
                            } catch (e: Exception) {
                                Log.e("API 응답 에러", "에러 본문을 읽는 중 에러가 발생했습니다.")
                            }
                        }
                    }

                    override fun onFailure(call: Call<getLogInResponse>, t: Throwable) {
                        // 네트워크 오류 등으로 요청 실패 처리
                        Log.e("로그인 호출 실패", "요청 실패: ${t.message}", t)
                    }
                })
            }
            
       
       kakao_login_button.setOnClickListener {

        if(UserApiClient.instance.isKakaoTalkLoginAvailable(this)){
               UserApiClient.instance.loginWithKakaoTalk(this, callback = callback)
         } else {
             UserApiClient.instance.loginWithKakaoAccount(this, callback = callback)
         }

**참고로 토큰 저장한 토큰 꺼낼때는 이 코드 사용!!!!!

val sharedPreferences = getSharedPreferences("my_token", Context.MODE_PRIVATE)
val accessToken = sharedPreferences.getString("access_token", null)

2. 회원가입 코드

1. 인터페이스 작성

이전과는 다른 형식의 Request였음..!!!!
신기하게 바디로 요청보내는게 아닌 @FormUrlEncoded
폼데이터를 보낼때 사용한다고 한다!! 키-값 쌍의 형태로 전송
[api 명세서에 적어주신 요청 예시]

--header 'Authorization: Bearer eyJ0eXAiOiJhY2Nlc3NfdG9rZW4iLCJhbGciOiJIUzI1NiJ9.eyJ1c2VySWQiOjAsImtha2FvSWQiOjMzNjgxNjE0NjAsImlhdCI6MTcwOTI5NzU0MSwiZXhwIjoxNzA5MzA0NzQxfQ.hU1kOJTWLEAhooJ6IvncpDtgDjsFXpQtractnsFLNZ8' \
--form 'enterprise="삼성"' \
--form 'type="IT"' \
--form 'email="dfsdfsdfsfds@fdsfsdfds"'

=> Field로 넣어주기

    @POST("주소")
    @FormUrlEncoded
    fun postSignUp(
        @Header("Authorization") authorization: String,
        @Field("enterprise") enterprise: String,
        @Field("type") type: String,
        @Field("email") email: String
    ): Call<SignUpResponse>

2. 로그인에서 회원이 아닌 경우,, 온보딩으로 넘어가는데 이때 온보딩1,2에서 작성한 회사와 회사타입을 인텐트로 최종 온보딩으로 넘겨주기

3. 최종 온보딩에서 api 호출하기

    private fun postCompanyInfo(email : String){

       //인텐트로 데이터 전부 넘겨받기
        val companyName = intent.getStringExtra("companyName")
        val companyType = intent.getStringExtra("companyType")
        val accessToken = intent.getStringExtra("accessToken")
        Log.d("토큰",accessToken.toString())
        Log.d("이름",companyName.toString())
        Log.d("타입1",companyType.toString())


        RetrofitClient.login.postSignUp("Bearer ${accessToken}", companyName.toString(), companyType.toString(), email)
            .enqueue(object : Callback<SignUpResponse> {
                override fun onResponse(call: Call<SignUpResponse>, response: Response<SignUpResponse>) {
                    if (response.isSuccessful) {
                        // 회원가입 성공
                        val signUpResponse: SignUpResponse? = response.body()
                        Log.d("성공", signUpResponse.toString())
                        // 처리할 작업 수행
                    } else {
                        // 회원가입 실패
                        val errorMessage = "요청 실패: ${response.code()} ${response.message()}"
                        Log.e("API 요청 실패", errorMessage)
                        // 추가 정보 출력
                        try {
                            val errorBody = response.errorBody()?.string()
                            Log.e("API 응답 에러", errorBody ?: "에러 응답 본문이 없습니다.")
                        } catch (e: Exception) {
                            Log.e("API 응답 에러", "에러 본문을 읽는 중 에러가 발생했습니다.")
                        }
                    }
                }


                override fun onFailure(call: Call<SignUpResponse>, t: Throwable) {
                    // 네트워크 오류 등으로 요청 실패
                    val errorMessage = "요청 실패: ${t.message}"
                    Log.e("API 요청 실패!", errorMessage, t)

                }
            })
    }

로직을 이해못해 조금 헤맸지만 +서버 키값 오류 이슈
구현하고나니깐 로그인 로직이 좀 더 잘 이해가 되었다!!
뿌듯--^^

내일 개강.. 그리고 기업 프로젝트 마감까지 화이팅..!!!

profile
개발을 공부하고 있는 대학생

0개의 댓글

관련 채용 정보