天天看点

Python:OAuth2第三方登录之Github

一、应用登记

https://github.com/settings/applications/new

登记完成后,获取两个参数

  1. 客户端 ID(client ID)
  2. 客户端密钥(client secret)

二、GitHub登录授权

1、网站让用户跳转到 GitHub。

GET https://github.com/login/oauth/authorize?
    client_id=7e015d8ce32370079895&
    redirect_uri=http://localhost:8080/oauth/redirect      

两个参数:

  1. client_id告诉 GitHub 谁在请求
  2. redirect_uri是稍后跳转回来的网址

2、 GitHub 用户登录授权,重定向回网站,同时返回【授权码code】。

GET http://localhost:8080/oauth/redirect?
    code=859310e7cecc9196f4af      

3、 网站后台使用授权码,向 GitHub 请求【令牌】, 需要加json请求头

POST https://github.com/login/oauth/access_token

Accept: application/json

参数:
client_id:客户端的 ID
client_secret:客户端的密钥
code:授权码      

三、请求数据

网站使用令牌,向 GitHub 请求用户数据。

GET https://api.github.com/user

Authorization: Bearer {access_token}
Accept: application/json      

代码实现

依赖requirements.txt

requests
flask
environs
mo-cache      

run.py

# -*- coding: utf-8 -*-
from urllib.parse import urljoin

from flask import Flask, request, url_for

from github_api import get_github_auth_url, user, get_access_token
from mo_cache import FileCache
from environs import Env

# 注册应用获取的参数
env = Env()
env.read_env()

clientID = env.str('clientID')
clientSecret = env.str('clientSecret')

# 使用文件缓存 access_token
cache = FileCache()

ACCESS_TOKEN_KEY = 'access_token_key'

app = Flask(__name__)


def full_url_for(endpoint, **values):
    """获取完整路径"""
    return urljoin(request.host_url, url_for(endpoint, **values))


@app.route('/')
def hello_world():
    """首页暴露接口地址"""
    return {
        'auth_url': full_url_for('get_auth_url'),
        'get_user': full_url_for('get_user')
    }


@app.route('/auth_url')
def get_auth_url():
    """获取由后端拼接的Github第三方登录授权地址"""
    redirect_uri = full_url_for('oauth_redirect')

    auth_url = get_github_auth_url(client_id=clientID, redirect_uri=redirect_uri)

    return {'auth_url': auth_url}


@app.route('/oauth/redirect')
def oauth_redirect():
    """github验证回调地址,从请求参数中获取code"""
    code = request.args.get('code')

    # 拿到code后继续请求获取access_token
    res = get_access_token(client_id=clientID, client_secret=clientSecret, code=code)

    # 存储用户的access_token
    access_token = res.get('access_token')
    cache.set(ACCESS_TOKEN_KEY, access_token)
    return res


@app.route('/user')
def get_user():
    """通过access_token 获取用户信息"""
    # 从缓存中取出
    access_token = cache.get(ACCESS_TOKEN_KEY)

    res = user(access_token=access_token)

    return res


if __name__ == '__main__':
    print(app.url_map)
    # 服务地址需要和应用配置一致
    app.run(port=8080, debug=True)
      

github_apipy

# -*- coding: utf-8 -*-

import requests


def get_github_auth_url(client_id, redirect_uri):
    """

    :param client_id: 告诉 GitHub 谁在请求
    :param redirect_uri: 跳转回来的网址
    :return:
    """
    authorize_uri = 'https://github.com/login/oauth/authorize'

    return f'{authorize_uri}?client_id={client_id}&redirect_uri={redirect_uri}'


def get_access_token(client_id, client_secret, code):
    """获取 access_token 此操作在后台完成"""
    url = 'https://github.com/login/oauth/access_token'

    params = {
        'client_id': client_id,
        'client_secret': client_secret,
        'code': code
    }

    headers = {
        'accept': 'application/json'
    }

    res = requests.post(url=url, params=params, headers=headers)

    return res.json()


def user(access_token):
    """获取用户信息"""
    url = 'https://api.github.com/user'

    headers = {
        'Authorization': f'Bearer {access_token}'
    }

    res = requests.get(url=url, headers=headers)

    return res.json()
      
Python

实现完整代码:

https://github.com/mouday/github-oauth-demo
参考 GitHub OAuth 第三方登录示例教程