Image_Us-소셜로그인

codakcodak·2023년 2월 27일
0

ImageUs

목록 보기
10/17

문제상황

  • 서비스 자체에 회원가입을 하는 절차가 불편하다.

해결방법

  • 이미 인증된 이메일로 가입 된 카카오나 네이버 등의 오픈 api를 이용하여 회원의 정보를 받아와 간편하게 회원가입을 하는 소셜로그인 서비스를 제공한다.

소셜로그인 절차

1.클라이언트는 프론트엔드를 통해 서비스의 키값과 함께 소셜 기업의 로그인으로 진입
2.로그인이 성공하면 미리 설정한 redirect url로 소셜 기업이 code값과 함께 redirect
3.redirect를 받은 서버는 전달 받은 code값을 가지고 소셜 기업에 access_token을 요청
4.access_token을 전달받은 서버는 다시 회원의 정보를 요청
5.회원의 정보를 가지고 로직 처리하여 프론트엔드에게 회원의 access_token 발급

구조도

상세코드

  1. db스키마 수정
CREATE TABLE `users` (
  `id` int NOT NULL AUTO_INCREMENT,
  `email` varchar(255) NOT NULL,
  `hashed_password` varchar(255) NOT NULL,
  `profile` varchar(255) NOT NULL,
  `deleted` boolean not null DEFAULT 0,
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `updated_at` timestamp NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
  `name` varchar(255) NOT NULL,
  `type` varchar(255) NOT NULL DEFAULT 'image_us'
  PRIMARY KEY (`id`),
  UNIQUE KEY `email` (`email`)
)
  • type이란 필드를 새롭게 추가하여 회원의 회원가입 유형을 kakao,naver,image_us의 3가지로 저장
  1. 클래스 선언(전체코드)
  class Oauth:
      default_headers={
              "Content-Type": "application/x-www-form-urlencoded",
              "Cache-Control": "no-cache",
          }

      corperation={'kakao':{
              "auth_url":"https://kauth.kakao.com/oauth/token",
              "profile_url":"https://kapi.kakao.com/v2/user/me"

          },
          'naver':{
              "auth_url":"https://nid.naver.com/oauth2.0/token",
              "profile_url":"https://openapi.naver.com/v1/nid/me"
      }}

      def __init__(self):
          pass

      def get_access_token(self,coperation,code,rest_api_key,secret_key,redirect_url):
          print(code)
          return requests.post(
          url=self.corperation.get(coperation)['auth_url'],
          headers=self.default_headers
              ,
          data={
                      "grant_type": "authorization_code",
                      "client_id": rest_api_key,
                      "client_secret": secret_key,
                      "redirect_uri": redirect_url,
                      "code": code
                  },
          ).json()

      def get_user_info(self,coperation,access_token):
          return requests.get(
          url=self.corperation.get(coperation)['profile_url'],
          headers={
              **self.default_headers,
              "Authorization":f"Bearer {access_token}"
              },
          data={}
          ).json()
  • 네이버와 카카오에 공통적으로 들어갈 헤더를 기본값으로 선언
default_headers={
            "Content-Type": "application/x-www-form-urlencoded",
            "Cache-Control": "no-cache",
        }
  • 네이버와 카카오의 openapi url을 클래스 변수로 선언
corperation={'kakao':{
            "auth_url":"https://kauth.kakao.com/oauth/token",
            "profile_url":"https://kapi.kakao.com/v2/user/me"

        },
        'naver':{
            "auth_url":"https://nid.naver.com/oauth2.0/token",
            "profile_url":"https://openapi.naver.com/v1/nid/me"
    }}
  • 소셜기업의 회원 정보를 받아올 수 있는 access_token을 받아오는 요청 메서드 정의
 def get_access_token(self,coperation,code,rest_api_key,secret_key,redirect_url):
        print(code)
        return requests.post(
        url=self.corperation.get(coperation)['auth_url'],
        headers=self.default_headers
            ,
        data={
                    "grant_type": "authorization_code",
                    "client_id": rest_api_key,
                    "client_secret": secret_key,
                    "redirect_uri": redirect_url,
                    "code": code
                },
        ).json()
  • access_token을 통해 소셜 기업의 개인 정보를 받아오는 요청 메서드 정이
def get_user_info(self,coperation,access_token):
        return requests.get(
        url=self.corperation.get(coperation)['profile_url'],
        headers={
            **self.default_headers,
            "Authorization":f"Bearer {access_token}"
            },
        data={}
        ).json()
  1. route(전체코드)
     oauth_login_callback_parser=api_parser_module.get_parser(['code','coperation'])
      @oauth_namespace.route("/callback")
      @oauth_namespace.expect(oauth_login_callback_parser,validate=False)
      class oauth_signup(Resource):
          def get(self):
              code=request.args['code']
              coperation=request.args['coperation']

              if coperation=="kakao":
                  token=oauth.get_access_token(coperation,code,config['KAKAO_REST_API_KEY'],config['KAKAO_SECRET_KEY'],config['KAKAO_REDIRECT_URI'])
                  print(token)
                  access_token=token['access_token']

                  res=oauth.get_user_info(coperation,access_token)
                  kakao_account_info=res['kakao_account']
                  oauth_user_info={
                      'name':kakao_account_info['profile']['nickname'],
                      'email':kakao_account_info['email'],
                      'password':str(res['id'])
                  }
              if coperation=="naver":
                  token=oauth.get_access_token(coperation,code,config['NAVER_REST_API_KEY'],config['NAVER_SECRET_KEY'],config['NAVER_REDIRECT_URI'])
                  print(token)
                  access_token=token['access_token']

                  res=oauth.get_user_info(coperation,access_token)
                  naver_account_info=res['response']
                  oauth_user_info={
                      'name':naver_account_info['name'],
                      'email':naver_account_info['email'],
                      'password':naver_account_info['id']
                  }

              if user_service.is_email_exists(oauth_user_info['email'],type=coperation):
                  user_info=user_service.get_user_id_and_password(email=oauth_user_info['email'],type=coperation)

                  access_token=user_service.generate_access_token(user_info['id'])

                  return make_response(jsonify({'access_token':access_token,'user_id':user_info['id']}))
              else:
                  new_user={
                      **oauth_user_info,
                      'profile':f"{coperation} 유저 입니다."
                  }
                  print(new_user)
                  new_user_id=user_service.create_new_user(new_user,type=coperation)

                  access_token=user_service.generate_access_token(new_user_id)
                  res=make_response(jsonify({'access_token':access_token,'user_id':new_user_id}))
                  res.headers["Access-Control-Allow-Origin"]="*"
                  return res
  • query string 값에서 code와 기업이름을 추출하여 기업에 따른 access_token과 기업의 회원 정보를 추출
            code=request.args['code']
            coperation=request.args['coperation']

            if coperation=="kakao":
                token=oauth.get_access_token(coperation,code,config['KAKAO_REST_API_KEY'],config['KAKAO_SECRET_KEY'],config['KAKAO_REDIRECT_URI'])
                print(token)
                access_token=token['access_token']

                res=oauth.get_user_info(coperation,access_token)
                kakao_account_info=res['kakao_account']
                oauth_user_info={
                    'name':kakao_account_info['profile']['nickname'],
                    'email':kakao_account_info['email'],
                    'password':str(res['id'])
                }
            if coperation=="naver":
                token=oauth.get_access_token(coperation,code,config['NAVER_REST_API_KEY'],config['NAVER_SECRET_KEY'],config['NAVER_REDIRECT_URI'])
                print(token)
                access_token=token['access_token']

                res=oauth.get_user_info(coperation,access_token)
                naver_account_info=res['response']
                oauth_user_info={
                    'name':naver_account_info['name'],
                    'email':naver_account_info['email'],
                    'password':naver_account_info['id']
                }
  • 기업에서 받아온 회원의 이메일 정보가 이미 존재한다면 바로 access_token을 발급하고 아니라면 회원가입 후 발급한다.
            if user_service.is_email_exists(oauth_user_info['email'],type=coperation):
                user_info=user_service.get_user_id_and_password(email=oauth_user_info['email'],type=coperation)
                    
                access_token=user_service.generate_access_token(user_info['id'])

                return make_response(jsonify({'access_token':access_token,'user_id':user_info['id']}))
            else:
                new_user={
                    **oauth_user_info,
                    'profile':f"{coperation} 유저 입니다."
                }
                print(new_user)
                new_user_id=user_service.create_new_user(new_user,type=coperation)
    
                access_token=user_service.generate_access_token(new_user_id)
                res=make_response(jsonify({'access_token':access_token,'user_id':new_user_id}))
                res.headers["Access-Control-Allow-Origin"]="*"
                return res
profile
숲을 보는 코더

0개의 댓글