前言:個人在學(xué)院易班技術(shù)部工作霜威,要求開發(fā)的項目要和易班結(jié)合,于是我在原來的在線問卷系統(tǒng)中添加了易班聯(lián)合登錄模塊,這也是本篇文章介紹的重點贡这。
1. 前期準備
易班開放平臺:https://open.yiban.cn/,申請開發(fā)者賬號厂榛,創(chuàng)建網(wǎng)絡(luò)應(yīng)用盖矫,這里不過多介紹這個丽惭。
為了方便本地測試,我們把網(wǎng)站和回調(diào)地址設(shè)置成本地地址:
2. 網(wǎng)站后端開發(fā)
-
弄懂易班的授權(quán)機制
授權(quán)機制的具體介紹:
https://open.yiban.cn/wiki/index.php?page=%E6%8E%88%E6%9D%83%E6%9C%BA%E5%88%B6%E8%AF%B4%E6%98%8E
歸納起來大體分成四個部分:
- 重定向至授權(quán)頁面
- 頁面返回用戶令牌code
- 用用戶令牌code換區(qū)用戶授權(quán)憑證
- 用access_token調(diào)用API獲取相關(guān)信息炼彪。
前兩步重定向由前端完成吐根,獲取用戶令牌后的操作在后端完成,目的是從API中獲取易班id和用戶名
-
創(chuàng)建APP
命令行執(zhí)行python manage.py startapp oauth
創(chuàng)建聯(lián)合登錄的應(yīng)用
-
配置url
Prj目錄下的urls.py的urlpattens中增加path('oauth/', include('oauth.urls')),
oauth的urls.py
from django.urls import path
from . import views
urlpatterns = [
path('login/', views.yb_login, name='yb_login'),
path('check/', views.yb_check, name='yb_check'),
path('bind/', views.yb_bind, name='yb_bind'),
]
-
編輯models
由于之前已經(jīng)建立好用戶登錄注冊模型了辐马,為了減少改動拷橘,我們創(chuàng)建一個新模型將用戶和易班id關(guān)聯(lián)。
models.py
from django.db import models
from django.contrib.auth.models import User
# Create your models here.
class OAuthyb(models.Model):
"""yb and User Bind"""
user = models.ForeignKey(User, on_delete=models.DO_NOTHING) # 關(guān)聯(lián)用戶信息表
yb_id = models.CharField(max_length=64) # yb_id
-
實現(xiàn)重定向到授權(quán)頁面
在oauth目錄下創(chuàng)建新文件oauth_client.py喜爷,這個文件用來封裝聯(lián)合登錄類
編輯oauth_client.py
import json
from urllib import parse
import requests
class OAuth:
def __init__(self, APPID, APPSECRET, CALLBACK):
self.app_id = APPID
self.key = APPSECRET
self.redirect_url = CALLBACK
def get_auth_url(self):
params = {
'client_id': self.app_id,
'redirect_uri': self.redirect_url,
'state': 1,
}
url = 'https://oauth.yiban.cn/code/html?%s' % parse.urlencode(params)
return url
這里把聯(lián)合登錄封裝成一個類冗疮,含有一些必須屬性,同時get_auth_url
這個方法用于獲取重定向url檩帐,為什么這樣操作术幔,參照官方文檔第一步。
settings添加
APPID=XXX
APPSECRET=XXX
CALLBACK=XXX
# 這里的都是你申請的信息湃密,注意要大寫诅挑,否則會出現(xiàn)很多BUG
編輯views.py
from django.shortcuts import render
from django.conf import settings
from .oauth_client import OAuth
from django.shortcuts import HttpResponseRedirect
from .models import OAuthyb
from django.contrib import auth
from django.urls import reverse
from .forms import YBLoginForm
# Create your views here.
def yb_login(request):
oauth_yb = OAuth(settings.APPID, settings.APPSECRET, settings.CALLBACK)
url = oauth_yb.get_auth_url()
return HttpResponseRedirect(url)
前面這些引入的文件,有的是后面用到的泛源,這一步完成后拔妥,就可以重定向到授權(quán)頁面了:
訪問本地頁面 http://127.0.0.1:8000/oauth/login
授權(quán)完成后會攜帶用戶令牌重定向到設(shè)置的CALLBACK頁面
-
編寫回調(diào)頁面處理函數(shù)獲取access_token和user_info
首先修改前面創(chuàng)建的OAuth類文件:
oauth_client.py
import json
from urllib import parse
import requests
class OAuth:
def __init__(self, APPID, APPSECRET, CALLBACK):
self.app_id = APPID
self.key = APPSECRET
self.redirect_url = CALLBACK
#獲取授權(quán)頁面的url
def get_auth_url(self):
params = {
'client_id': self.app_id,
'redirect_uri': self.redirect_url,
'state': 1,
}
url = 'https://oauth.yiban.cn/code/html?%s' % parse.urlencode(params)
return url
#獲取access_token的值,寫入類并回調(diào)
def get_access_token(self, code):
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36',
'X-Requested-With': 'XMLHttpRequest'
}
params = {
'code': code,
'client_id': self.app_id,
'client_secret': self.key,
'redirect_uri': self.redirect_url,
}
url = 'https://oauth.yiban.cn/token/info?%s' % parse.urlencode(params)
response = requests.get(url=url, headers=headers)
response.encoding = 'utf-8'
result = json.loads(response.text)
access_token = str(result['access_token'])
self.access_token = access_token
return access_token
# 獲取用戶信息达箍,轉(zhuǎn)換為json文件并回調(diào)
def get_yb_info(self):
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36',
'X-Requested-With': 'XMLHttpRequest'
}
params = {
'access_token': self.access_token,
}
url = 'https://openapi.yiban.cn/user/me?%s' % parse.urlencode(params)
response = requests.get(url=url, headers=headers)
response.encoding = 'utf-8'
result = json.loads(response.text)
return result
增加的方法功能都寫在注釋里面了没龙,所有的流程都是參照著官方文檔來的,用到了requests庫來在后端獲取access_token和用戶信息
編輯views.py
def yb_check(request):
request_code = request.GET.get('code')
oauth_yb = OAuth(settings.APPID, settings.APPSECRET, settings.CALLBACK)
access_token = oauth_yb.get_access_token(request_code)
print('access_key=%s' % access_token)
# 獲取用戶信息
infos = oauth_yb.get_yb_info()
if infos['status'] == 'success':
user_id = infos['info']['yb_userid']
user_name = infos['info']['yb_username']
# ORM查找易班id是否已綁定
id_models = OAuthyb.objects.filter(yb_id=user_id)
# 已綁定缎玫,直接登錄
if id_models:
user = id_models[0].user
user.backend = 'django.contrib.auth.backends.ModelBackend'
auth.login(request, user)
return HttpResponseRedirect(reverse('home'))
# 未綁定硬纤,攜帶信息跳轉(zhuǎn)到跳轉(zhuǎn)到綁定頁面
else:
url = '%s?user_id=%s&user_name=%s' % (reverse('yb_bind'), user_id, user_name)
return HttpResponseRedirect(url)
# 獲取用戶信息失敗返回錯誤信息
else:
context = {}
context['message'] = infos['info']['msgCN']
return render(request, 'message.html', context)
思路就是獲取access_token后攜帶access_token獲取用戶信息,然后按提示綁定賬戶
-
用戶綁定易班id
使用djangoform赃磨。只含有和已注冊用戶綁定筝家,綁定未注冊賬戶尚未完善
新建forms.py
from django import forms
from django.contrib.auth.models import User
from django.contrib import auth
from .models import OAuthyb
class YBLoginForm(forms.Form):
username = forms.CharField(label='用戶名',
widget=forms.TextInput(attrs={'class': 'form-control', 'placeholder':'請輸入用戶名'}))
password = forms.CharField(label='密碼',
widget=forms.PasswordInput(attrs={'class': 'form-control', 'placeholder':'請輸入密碼'}))
user_id = forms.CharField(label='', widget=forms.HiddenInput(attrs={'id': 'user_id'}))
def clean(self):
username = self.cleaned_data['username']
password = self.cleaned_data['password']
user = auth.authenticate(username=username, password=password)
if user is None:
raise forms.ValidationError("用戶名或者密碼不正確")
else:
self.cleaned_data['user'] = user
return self.cleaned_data
def clean_user_id(self):
user_id = self.cleaned_data['user_id']
if OAuthyb.objects.filter(user_id=user_id).exists():
raise forms.ValidationError('該ID已綁定其他賬號')
return user_id
views.py增加
def yb_bind(request):
if request.method == 'POST':
login_form = YBLoginForm(request.POST)
if login_form.is_valid():
user_id = login_form.cleaned_data['user_id']
user = login_form.cleaned_data['user']
oauth_obj = OAuthyb()
oauth_obj.yb_id = user_id
oauth_obj.user = user
oauth_obj.save()
auth.login(request, user)
return HttpResponseRedirect(reverse('home'))
else:
login_form = YBLoginForm()
context = {}
context['login_form'] = login_form
context['user_id'] = request.GET.get('user_id')
context['user_name'] = request.GET.get('user_name')
return render(request, 'yb_login_bind.html', context)
yb_login_bind.html
{% extends 'base.html' %}
{% block title%}
在線填表系統(tǒng)|登錄
{% endblock %}
{% block css_header %}
<link rel="stylesheet" href="/static/home.css">
{% endblock %}
{% block content %}
<div class="row">
<div class="col-xs-4 col-xs-offset-4">
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">登錄</h3>
</div>
<div class="panel-body">
<h4> 歡迎你,易班用戶<b class="text-primary">{{ user_name }}</b><br>請綁定后繼續(xù)</h4>
{% if not user.is_authenticated %}
<form action="" method="POST">
{% csrf_token %}
{% for field in login_form %}
<label for="{{ field.id_for_label }}">{{ field.label }}</label>
{{ field }}
<p class="text-danger">{{ field.errors.as_text }}</p>
{% endfor %}
<span class="pull-left text-danger">{{ login_form.non_field_errors }}</span>
<input type="submit" value="登錄" class="btn btn-default pull-right">
</form>
{% else %}
<div><span>用戶 <strong>{{ user.username }}</strong> 已登錄邻辉,請勿重復(fù)登錄</span></div>
{% endif %}
</div>
</div>
</div>
</div>
<script src="/static/bootstrap-3.3.7/js/jquery.min.js"></script>
<script type="text/javascript">
$(document).ready(function() {
$('#user_id').val({{ user_id }})
});
</script>
{% endblock %}
綁定頁面:
-
最終效果:
代碼github地址:待更新