애플 앱 출시를 하기위해 애플 로그인이 필요하다고 해서 구현하였다. 애플로그인을 구현하기 앞서, 애플 api와 연동을 해야한다.
초기 연결하는 법이 적혀 있는 블로그이다.(감사합니다)
https://tyrannocoding.tistory.com/65
[초간단] 애플 로그인 API 연동 초기 설정 하기
IOS 앱 배포를 위해 본인의 어플을 애플에 심사함에 있어, 소셜 로그인 기능을 사용하지만 애플 로그인이 없으면 reject사유가 되므로 전혀 고려하지 않은 애플 로그인을 만들게 되었습니다. 여
tyrannocoding.tistory.com
사용자의 데이터를 얻기 위해 필요한 데이터에는 TEAM_ID, CLIENT_ID, REDIRECT_URL, KEY_ID, *.p8 파일이다.
그리고 PyJWT 설치가 필요하다.
pip install pyjwt[crypto]
먼저 애플 로그인 화면을 띄어줄 코드이다.
from flask import jsonify
@app.route('/aauth/url', methods=['GET'])
def get_apple_oauth_url():
return jsonify(
oauth_url = "https://appleid.apple.com/auth/authorize?"+\
"client_id="+app.config['CLIENT_ID']+\
"&redirect_uri="+app.config['REDIRECT_URI']+\
"&response_type=code id_token&scope=name email&response_mode=form_post"\
)
client_id와 redirect_uri에 각각 가져온 데이터를 넣어서 보내면 된다. response_type의 code는 사용자가 로그인을 성공했을 때 토큰 검증을 위해 redirect_uri로 form 형태로 넘어온다.
다음은 모델 코드이다.
class AppleAuth:
ACCESS_TOKEN_URL='https://appleid.apple.com/auth/token'
def __init__(self, code):
self.code = code
def request_apple_auth(self):
client_secret = self.get_client_secret()
headers = {'content-type': "application/x-www-form-urlencoded"}
data = {
'client_id': app.config["CLIENT_ID"],
'client_secret': client_secret,
'code': self.code,
'grant_type': 'authorization_code',
'redirect_uri': app.config['REDIRECT_URL']
}
res = requests.post(AppleAuth.ACCESS_TOKEN_URL, data=data, headers=headers)
return res
def get_client_secret(self):
headers = {
'kid': app.config['KEY_ID']
}
payload = {
'iss': app.config['TEAM_ID'],
'iat': datetime.now(),
'exp': datetime.now() + timedelta(minutes=10),
'aud': 'https://appleid.apple.com',
'sub': app.config['CLIENT_ID']
}
key = self.get_auth_key()
client_secret = jwt.encode(
payload,
key,
algorithm='ES256',
headers=headers
)
return client_secret
def get_auth_key(self):
base_dir = os.getcwd()
f = open(f'{base_dir}/*.p8(파일)')
key = f.read()
f.close()
return key
전체적인 흐름은 https://appleid.apple.com/auth/token 이 uri로 id_token 발급 및 토큰 검증하는 흐름이다.
(id_token에는 유저의 정보가 들어있다.)
# AppleAuth.get_client_secret
def get_client_secret(self):
headers = {
'kid': app.config['KEY_ID']
}
payload = {
'iss': app.config['TEAM_ID'],
'iat': datetime.now(),
'exp': datetime.now() + timedelta(minutes=10),
'aud': 'https://appleid.apple.com',
'sub': app.config['CLIENT_ID']
}
key = self.get_auth_key()
client_secret = jwt.encode(
payload,
key,
algorithm='ES256',
headers=headers
)
return client_secret
먼저 client_secret을 만들어야한다. key의 경우 .p8의 내용을 담으면 된다. (get_auth_key함수 참고)
(payload에 exp는 토큰 만료시간이다. 너무 길게하면 400 error가 발생한다.)
이제 POST로 https://appleid.apple.com/auth/token 이 URI로 요청하면 된다.
# AppleAuth.request_apple_auth
def __init__(self, code):
self.code = code
def request_apple_auth(self):
client_secret = self.get_client_secret()
headers = {'content-type': "application/x-www-form-urlencoded"}
data = {
'client_id': app.config["CLIENT_ID"],
'client_secret': client_secret,
'code': self.code,
'grant_type': 'authorization_code',
'redirect_uri': app.config['REDIRECT_URL']
}
res = requests.post(AppleAuth.ACCESS_TOKEN_URL, data=data, headers=headers)
return res
로그인 성공을 하여 받은 code와 위에서 생성한 client_secret을 data에 넣어 요청하면 된다.
이제 미리 설정한 redirect uri의 코드만 짜면 된다.
@app.route('/aauth', methods=['POST'])
def apple_auth():
code = request.form.get("code")
apple_auth = AppleAuth(code)
res = apple_auth.request_apple_auth()
if res.status_code != 200:
return res.status_code
res_dict = res.json()
key = apple_auth.get_auth_key()
id_token = res_dict.get('id_token', None)
if id_token:
decoded = jwt.decode(id_token, key=key, algorithms='RS256', options={'verify_signature': False})
email = decoded['email']
# 이후 코드는 서비스에 맞게
# 회원가입, 로그인 처리
먼저 로그인 성공시 받는 code를 form으로 받는다
AppleAuth 객체를 생성하고 애플로 요청을 보내면 된다. 넘어온 response에 있는 id_token을 복호화하면 email정보가 있다.
이 정보로 서비스에 맞게 회원가입 혹은 로그인 처리를 하면 될 듯하다.