Django 如何正确接入 GitHub OAuth?

项目地址: https://github.com/hsowan/CSDNBot/tree/web

首先, 创建 GitHub OAuth Apps

{% img /images/new-github-oauth-app.png %}

其中值得注意的有:

  • Authorization callback URL (认证后的回调地址), 比如: http://localhost:8000/api/login/oauth/code/github/, 在认证之后将跳转到这个地址并带上一个 code 参数, 这个参数会用来请求 access_token
  • Client IDClient Secret 也是用户请求 access_token 的参数

然后, 在 Django 项目中添加路由

from django.urls import re_path
from . import apis

urlpatterns = [
    re_path(r'^api/login/oauth/code/github/?$', apis.github_oauth_callback),
]

实现 github_oauth_callback:

import requests
from django.conf import settings
import json
from django.shortcuts import redirect

# https://github.com/login/oauth/authorize?client_id=bd4692513cb71ba05c22&scope=user
def github_oauth_callback(request):
    code = request.GET.get('code', '')

    # 没有 code 参数时的处理
    if code == '':
        return redirect('/')

    data = {
        'client_id': settings.GITHUB_CLIENT_ID,
        'client_secret': settings.GITHUB_CLIENT_SECRET,
        'code': code
    }

    github_api_base_url = 'https://api.github.com'
    get_access_token_url = 'https://github.com/login/oauth/access_token'

    r = requests.post(get_access_token_url, data)
    content = r.content.decode('utf-8')
    if r.status_code == 200:
        # content: access_token=e72e16c7e42f292c6912e7710c838347ae178b4a&token_type=bearer
        access_token = content.split('&')[0].split('=')[1]
        headers = {
            'Authorization': 'token ' + access_token,
        }
        # Get user
        get_user_url = github_api_base_url + '/user'
        get_user_res = requests.get(get_user_url, headers=headers)
        content = get_user_res.content.decode('utf-8')
        if get_user_res.status_code == 200:
            # Refer: https://developer.github.com/v3/users/#get-a-single-user
            github_user = json.loads(content)
            # 省略持久化的操作
        else:
            print('GitHub 登录失败: ' + str(get_user_res.status_code) + ', ' + content)
            return redirect('/')

    else:
        print('GitHub 登录失败: ' + str(r.status_code) + ', ' + content)
        return redirect('/')

    # 将用户信息保存到session
    request.session['github_id'] = github_id
    return redirect('/')

现在就可以访问 https://github.com/login/oauth/authorize?client_id=your_client_id&scope=user 实现 GitHub 登录, 其中需要 client_idscope 两个参数, scope 表示认证后请求到的 access_token 可以使用哪些 API, 具体参考 Understanding scopes for OAuth Apps