Django使用OAuth2.0协议认证GitHub

OAuth2.0介绍

OAuth 2.0是行业标准的授权协议。 OAuth 2.0取代了2006年创建的原始OAuth协议所做的工作.OAuth 2.0专注于简化客户开发人员,同时为Web应用程序,桌面应用程序,手机和客厅设备提供特定的授权流程。具体协议参照RFC官方文档

OAuth2.0工作流程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
+--------+                               +---------------+
| |--(A)- Authorization Request ->| Resource |
| | | Owner |
| |<-(B)-- Authorization Grant ---| |
| | +---------------+
| |
| | +---------------+
| |--(C)-- Authorization Grant -->| Authorization |
| Client | | Server |
| |<-(D)----- Access Token -------| |
| | +---------------+
| |
| | +---------------+
| |--(E)----- Access Token ------>| Resource |
| | | Server |
| |<-(F)--- Protected Resource ---| |
+--------+ +---------------+

OAuth定义了四种角色

  • resource owner: 资源所有者,又称”用户”。
  • resource server: 资源服务器,能够接受并使用访问令牌响应受保护的资源请求。
  • client: 应用程序代表资源所有者及其授权进行受保护的资源请求,也就是浏览器。
  • authorization server: 认证服务器,即服务提供商专门用来处理认证的服务器。

角色之间的相互作用,包括以下步骤:

  • (A) 用户打开客户端以后,客户端要求用户给予授权。该授权请求可以直接给资源所有者(如图所示),或者优选间接通过授权服务器作为中介。
  • (B) 客户端收到授权许可,这是一个代表资源所有者授权的凭证,用本文定义的四种授权类型之一表示规范或使用扩展授权类型。
  • (C) 客户端使用上一步获得的授权,向认证服务器申请令牌。
  • (D) 认证服务器对客户端进行认证以后,确认无误,同意发放令牌。
  • (E) 客户端使用令牌,向资源服务器申请获取资源。
  • (F) 资源服务器确认令牌无误,同意向客户端开放资源。

Django利用GitHub开放的OAuth2.0接口实现认证

说明:以下为纯代码,如对GitHub不熟悉,请查阅相关资料。
这里我们只需要在GitHub上配置OAuth,获取到CLIENTID与CLIENTSECRET即可

  • views.py

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    import requests
    from django.http import HttpResponseRedirect
    from django.http import Http404
    from django.contrib.auth import authenticate, login
    from django.shortcuts import render
    from oauth.models import User
    from common.utils import randomString

    GITHUB_CLIENT_ID = 'github-client-id'
    GITHUB_CLIENT_SECERT = 'gitlub-client-secret'
    GITHUB_REDIRECT = 'https://github.com/login/oauth/authorize'
    GITHUB_EXCHANGE_TOKEN = 'https://github.com/login/oauth/access_token'
    GITHUB_USER = 'https://api.github.com/user'
    GITHUB_CALLBACK_URL = "http://www.youshutong.com/oauth/github"

    def github_redirect(request):
    random_string = randomString(10)
    request.session['github_state'] = random_string
    redirect_url = GITHUB_REDIRECT + \
    "?client_id=" + GITHUB_CLIENT_ID + \
    "&redirect_uri=" + GITHUB_CALLBACK_URL + \
    "&state=" + random_string
    return HttpResponseRedirect(redirect_url)

    def github_auth(request):
    code = request.GET.get('code')
    state = request.GET.get('state')
    save_state = request.session.get('github_state',"no")
    if save_state == state:
    params = {
    "client_id":GITHUB_CLIENT_ID,
    "client_secret":GITHUB_CLIENT_SECERT,
    "code":code,
    "state":state,
    "redirect_uri":GITHUB_CALLBACK_URL
    }
    headers = {"Accept":"application/json"}
    url = GITHUB_EXCHANGE_TOKEN
    r = requests.post(url, params=params, headers=headers)
    access_token = r.json()['access_token']
    params = {"access_token":access_token}
    response = requests.get(GITHUB_USER, params=params)
    json_result = response.json()
    username = json_result['login']
    alias = json_result['name']
    email = json_result['email']
    password = "youshutong@auto"
    try:
    User.objects.get(username=username, email=email)
    except:
    user = User.objects.create_user(
    username=username,
    email=email,
    password=password,
    alias=alias,
    auth_type='github'
    )
    user.save()

    user = authenticate(username=username, password=password)
    login(request, user)
    return render(request, 'blog/index.html', {"result":json_result, "auth_type": "github"})
    else:
    raise Http404()
  • urls.py

    1
    2
    url(r'^github-redirect/$', github_redirect, name='github-redirect'),
    url(r'^github/$', github_auth, name='github-auth'),

至此,github OAuth2.0认证就完成了,其它大型平台如QQ/微博/微信/Googel/Facebook都是使用类似方法,只是各家服务商的申请开放方式不一样,整体思路和代码逻辑都类似。