用Django2.1開發(fā)易班聯(lián)合登錄

前言:個人在學(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è)置成本地地址:

網(wǎng)站應(yīng)用信息設(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)過程介紹

歸納起來大體分成四個部分:

  • 重定向至授權(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)頁面

授權(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地址:待更新

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末溪王,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子恩沛,更是在濱河造成了極大的恐慌在扰,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,544評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件雷客,死亡現(xiàn)場離奇詭異芒珠,居然都是意外死亡,警方通過查閱死者的電腦和手機搅裙,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,430評論 3 392
  • 文/潘曉璐 我一進店門皱卓,熙熙樓的掌柜王于貴愁眉苦臉地迎上來裹芝,“玉大人,你說我怎么就攤上這事娜汁∩┮祝” “怎么了?”我有些...
    開封第一講書人閱讀 162,764評論 0 353
  • 文/不壞的土叔 我叫張陵掐禁,是天一觀的道長怜械。 經(jīng)常有香客問我,道長傅事,這世上最難降的妖魔是什么缕允? 我笑而不...
    開封第一講書人閱讀 58,193評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮蹭越,結(jié)果婚禮上障本,老公的妹妹穿的比我還像新娘。我一直安慰自己响鹃,他們只是感情好驾霜,可當(dāng)我...
    茶點故事閱讀 67,216評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著买置,像睡著了一般粪糙。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上堕义,一...
    開封第一講書人閱讀 51,182評論 1 299
  • 那天猜旬,我揣著相機與錄音脆栋,去河邊找鬼倦卖。 笑死,一個胖子當(dāng)著我的面吹牛椿争,可吹牛的內(nèi)容都是我干的怕膛。 我是一名探鬼主播,決...
    沈念sama閱讀 40,063評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼秦踪,長吁一口氣:“原來是場噩夢啊……” “哼褐捻!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起椅邓,我...
    開封第一講書人閱讀 38,917評論 0 274
  • 序言:老撾萬榮一對情侶失蹤柠逞,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后景馁,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體板壮,經(jīng)...
    沈念sama閱讀 45,329評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,543評論 2 332
  • 正文 我和宋清朗相戀三年合住,在試婚紗的時候發(fā)現(xiàn)自己被綠了绰精。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片撒璧。...
    茶點故事閱讀 39,722評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖笨使,靈堂內(nèi)的尸體忽然破棺而出卿樱,到底是詐尸還是另有隱情,我是刑警寧澤硫椰,帶...
    沈念sama閱讀 35,425評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站靶草,受9級特大地震影響涉馁,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜爱致,卻給世界環(huán)境...
    茶點故事閱讀 41,019評論 3 326
  • 文/蒙蒙 一烤送、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧糠悯,春花似錦帮坚、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,671評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至纫普,卻和暖如春阅悍,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背昨稼。 一陣腳步聲響...
    開封第一講書人閱讀 32,825評論 1 269
  • 我被黑心中介騙來泰國打工节视, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人假栓。 一個月前我還...
    沈念sama閱讀 47,729評論 2 368
  • 正文 我出身青樓寻行,卻偏偏與公主長得像,于是被迫代替她去往敵國和親匾荆。 傳聞我的和親對象是個殘疾皇子拌蜘,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,614評論 2 353

推薦閱讀更多精彩內(nèi)容