3
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

PythonでYahoo IDトークンの取得

Last updated at Posted at 2019-10-09

Yahoo IDトークンの取得用のRestクライアントをPythonで実装してみた。
先ずは、以下URLにアクセスし、でクライアントID・クライアントシークレット・コールバックURLの設定を行う。

Yahooディベロッパーネットワーク:
https://developer.yahoo.co.jp/yconnect

ログインの際にPOSTするパラメータは、ログイン画面からスクレイピングで取得することとなるが、どれが必須パラメータか不明だったので、とりあえず全てを対象にした。
※「.albatross」に関しては、ログインのサブミットの際に、Javascriptにより生成される値なので、Javascript実行箇所のパラメータをPOSTすることに注意。

#!/usr/bin/env python
# coding: utf-8

import requests
import base64
import random
import json
from bs4 import BeautifulSoup
from time import sleep

class GetAccessToken:
    def __init__(self):
        self.client_id = '*****' #クライアントID
        self.client_secret = '*****' #クライアントシークレット
        self.callback_url = '*****' #コールバックURL
        self.auth_base_url = 'https://auth.login.yahoo.co.jp'
        self.token_url = self.auth_base_url + '/yconnect/v2/token'
        self.login_base_url = 'https://login.yahoo.co.jp/config/login'
        self.account_edit_url = 'https://account.edit.yahoo.co.jp'
        self.nonce = random.randrange(10**31,10**32)
        base64_id_secret = self.client_id + ':' + self.client_secret
        base64_id_secret_byte = base64.b64encode(base64_id_secret.encode('utf-8'))
        self.auth_header = 'Basic ' + base64_id_secret_byte.decode('ascii')
        self.user_agent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36'
        self.http_version = 'HTTP/1.1'
        self.content_type = 'application/x-www-form-urlencoded; charset=utf-8'
        self.user_name = '*****' #メールアドレス
        self.passwd = '*****' #パスワード
        self.default_cookie = 'YJTC=ZwNLYKOz0Je_CyW9SGrcmya6TuK.jMk-; YLS=v=2&p=0&n=1;'
        self.yjbfp_items = 'uaMozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36langjascreen_height1080screen_width1920timezone_offset-540pluginsChrome PDF Plugin|Chrome PDF Viewer|Native Clientcanvas_imageiVBORw0KGgoAAAANSUhEUgAAABAAAAAWCAYAAADJqhx8AAAByUlEQVQ4T9WUv0vDUBSFv1AsaHUSxCylEmsddXGTgiJ2UhcFsY4OpaCIuLo4OQn+Dw61ILgFpJPoIDg4OLTWWlJKgqBYtFGMEnlP6s9apYrgnV6Sdw/3OznvKfywFNHvuhtuvTr/SGB9HXZ2YHUVGhtfgP8eYX/fxDCuGBnR8Ho9PE+wvOxSLCpvRnw99ubmFwi7uy7xOCQSCqEQ3NzA/Dz098PUFHzpwfm52OgSDucJBh26uzUWFjysrUGpZKLrVxSLGtPTZ1hWFQThq8AoFC7p6TFoaOjk4MDHysoD29snGEYLmYxKNGp+LpBOw9zcHUNDGdLpVsJhlcHBMrqex3ECUrCmQIVbVU85OnJYWtKw7TPpum1r7O15agsIDGFWPF5mYiLP4qKfw0MTv7+F42NVBqnmBEJAYExO3jM2lmNgoIlstkQkEiCV8n1fYHYWYjGTQsFCVX0yNMmk53sCAiGXc5mZsdnaytLb20Zfnyr/kKjhYat6Eis5ePJBwXGe3A+FAsRiTbJZhExkomqU318oIvMXF7dEIh1vPun6qXyuvP9wGq+v70gmM3LT+HgXzc1eubasskQSNTraSXu7T65/5zjXex+KvkcATSsyIKf0dAAAAABJRU5ErkJggg=='

    def get_az_code(self):
        s = requests.Session()

        headers = {
            'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3',
            'User-Agent': self.user_agent,
            'HTTP-Version': self.http_version,
            'Content-Type': self.content_type,
            'Connection': 'Keep-Alive',
        }

        url = self.auth_base_url + '/yconnect/v2/authorization?response_type=code&client_id=' +              self.client_id + '&redirect_uri=' + self.callback_url + '&scope=openid+profile&nonce=' + str(self.nonce)
        res = s.get(url, headers=headers)

        session_str = '%26session%3D'
        session_idx = res.url.find(session_str)
        session_id = res.url[session_idx+13:session_idx+21]

        res_redirect = s.get(res.url, headers=headers, cookies=s.cookies.get_dict())

        login_form_html = BeautifulSoup(res_redirect.text, 'html.parser')
        albatross_str = 'document.getElementsByName(".albatross")[0].value ='
        albatross_idx = login_form_html.text.find(albatross_str)
        albatross = login_form_html.text[albatross_idx+53: albatross_idx+109]
        bcrumb_id_check = login_form_html.find(attrs={'name': 'bcrumb_id_check'}).get('value')
        bcrumb_send_sms = login_form_html.find(attrs={'name': 'bcrumb_send_sms'}).get('value')
        bcrumb_send_mail = login_form_html.find(attrs={'name': 'bcrumb_send_mail'}).get('value')
        u = login_form_html.find(attrs={'name': 'u'}).get('value')
        done_url = self.auth_base_url + '/yconnect/v2/authorization?.scrumb=0&from=login&session=' +              session_id + '&display=page'
        reg_url = self.account_edit_url + '/registration?src=yconnectv2&done=https%3A%2F%2Fauth.login.yahoo.co.jp%2Fyconnect%2Fv2%2Fauthorization%3F.scrumb%3D0%26from%3Dlogin%26session%3' +             session_id + '%26display%3Dpage&ckey=' + self.client_id + '&.display=page'

        data = {
            '.ct': '',
            '.display': 'page',
            '.done': done_url,
            '.keep': '',
            '.reg': reg_url,
            '.src': 'yconnectv2',
            '.suppreg_skip': '',
            '.yby': '',
            'auth_lv': 'pin',
            'card_cushion_skip': '',
            'ckey': self.client_id,
            'nolink': '',
            'nonotice': '',
            'noreg': '',
            'referrer': '',
            't_cushion': '',
            '.albatross': albatross,
            '.requiredPsCheckBox': '',
            '.slogin': '',
            '.tries': '1',
            'ls_autocomp': '',
            'showpw_status': '',
            'u': u,
            'inactive_pw': '',
            'send_sms_counts': '1',
            'send_mail_counts': '1',
            'version': '',
            'auth_method': 'pwd',
            'pwless_captchaid': '',
            'sms_token': '',
            'mail_token': '',
            'masked_dest': '',
            'bcrumb_id_check': bcrumb_id_check,
            'bcrumb_send_sms': bcrumb_send_sms,
            'bcrumb_send_mail': bcrumb_send_mail,
            'user_name': self.user_name,
            'assertionInfo': '',
            'webauthn': '',
            'fido': '0',
            'auth_list': 'pwd',
            'login': self.user_name,
            'passwd': self.passwd,
            'code': '',
            'btnSubmit': '',
            'presistent': 'y',
            'yjbfp_items': self.yjbfp_items

        }

        res_login = s.post(self.login_base_url, data=data, headers=headers, cookies=s.cookies.get_dict())

        code_str = '?code='
        code_idx = res_login.url.find(code_str)
        az_code = res_login.url[code_idx+6:code_idx+14]

        return az_code

    def get_access_token(self, az_code):

        headers = {
            'HTTP-Version': self.http_version,
            'Content-Type': self.content_type,
            'Authorization': self.auth_header
            }

        data = {
            'grant_type': 'authorization_code',
            'code': az_code,
            'redirect_uri': self.callback_url
        }

        response = requests.post(self.token_url, data=data, headers=headers)
        access_token = response.json()['access_token']
        refresh_token = response.json()['refresh_token']

        return access_token, refresh_token

    def update_access_token(self, refresh_token):
        headers = {
            'HTTP-Version': self.http_version,
            'Content-Type': self.content_type,
            'Authorization': self.auth_header
            }

        data = {
            'grant_type': 'refresh_token',
            'refresh_token': refresh_token
            }

        response = requests.post(self.token_url, data=data, headers=headers)
        u_access_token = response.json()['access_token']

        return u_access_token
3
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?