Django + Taro 前后端分離項目實(shí)現(xiàn)企業(yè)微信登錄
前言
還是最近在做的一個小項目,后端用的是Django搭配RestFramework做接口,前端第一次嘗試用京東開源的Taro框架來做多端(目前需要做用于企業(yè)微信的H5端和微信小程序)
本文記錄一下企業(yè)微信登錄的流程,上周看文檔看得頭暈暈的,其實(shí)很簡單,封裝好了就幾行代碼的事~
兩種方式
一種是先拼接好登錄要用的地址 authorize_url,回調(diào)地址設(shè)置成h5應(yīng)用的網(wǎng)頁入口,然后把authorize_url設(shè)置為企業(yè)微信里的應(yīng)用主頁就行,然后直接提取鏈接里的code另一種是在應(yīng)用里拼接 authorize_url地址,回調(diào)地址同樣設(shè)置成h5應(yīng)用的網(wǎng)頁入口,然后應(yīng)用里去請求authorize_url,然后提取鏈接里的code用來登錄就行
說是兩種,其實(shí)流程都是一樣的,只不過第一種少去了前端拼接authorize_url以及首次請求的操作,為了方便起見,本文推薦使用第一種
思路
假設(shè)前端地址是http://xxx.com,那么我們用后端生成的企業(yè)微信登錄地址中會把前端地址作為回調(diào)地址傳入,在企業(yè)微信中訪問登錄地址之后,回跳轉(zhuǎn)到我們的前端地址,并在路徑中附上參數(shù)code,形式如下:
http://xxx.com?code=dkwawen123j13bk1
所以前端要做的就是拿到這串code,并提交給后端,讓后端拿code去微信服務(wù)器換用戶信息,就這樣~
后端代碼
企業(yè)微信登錄的接口已經(jīng)集成在我的「DjangoStarter」項目模板中,可以直接食用~
后端使用的是wechatpy這個庫,非常好用,封裝了微信開發(fā)的常用功能~
下面寫一下兩個關(guān)鍵的方法
from?django.conf?import?settings
from?django.contrib.auth?import?login
from?django.contrib.auth.models?import?User
from?rest_framework.authtoken.models?import?Token
from?drf_yasg2.utils?import?swagger_auto_schema
from?drf_yasg2?import?openapi
from?rest_framework.exceptions?import?APIException
from?rest_framework?import?viewsets
from?rest_framework.response?import?Response
from?rest_framework.request?import?HttpRequest
from?rest_framework.decorators?import?action
from?wechatpy.enterprise?import?WeChatClient
from?apps.core.serializers?import?UserSerializer
class?WechatWork(viewsets.ViewSet):
????"""微信企業(yè)號相關(guān)認(rèn)證服務(wù)"""
????client?=?WeChatClient(
????????settings.WECHAT_WORK_CONFIG['CORP_ID'],
????????settings.WECHAT_WORK_CONFIG['SECRET'],
????)
????@swagger_auto_schema(operation_summary='獲取微信企業(yè)號登錄鏈接')
????@action(detail=False)
????def?get_authorize_url(self,?request):
????????return?Response({
????????????#?todo?這里要寫上前端應(yīng)用入口地址
????????????'url':?self.client.oauth.authorize_url('http://xxx.com')
????????})
????@swagger_auto_schema(
????????operation_summary='通過code登錄',
????????manual_parameters=[
????????????openapi.Parameter(
????????????????name='code',?in_=openapi.IN_QUERY,
????????????????description='從微信企業(yè)號服務(wù)器獲取到的code',
????????????????type=openapi.TYPE_STRING)
????????])
????@action(detail=False,?methods=['POST'])
????def?login_by_code(self,?request:?HttpRequest):
????????code?=?request.GET.get('code',?None)
????????try:
????????????user_info?=?self.client.oauth.get_user_info(code)
????????except?Exception?as?e:
????????????raise?APIException(detail=e)
????????phone?=?user_info['UserId']
????????is_created_user?=?False
????????if?User.objects.filter(username=phone).exists():
????????????user_obj:?User?=?User.objects.get(username=phone)
????????else:
????????????is_created_user?=?True
????????????user_obj:?User?=?User.objects.create_user(username=phone,?password=phone)
????????#?記錄Django登錄狀態(tài)
????????login(request,?user_obj)
????????#?生成drf?token
????????token,?created?=?Token.objects.get_or_create(user=user_obj)
????????return?Response({
????????????'user':?UserSerializer(user_obj).data,
????????????'user_info':?user_info,
????????????'successful':?True,
????????????'is_created_user':?is_created_user,
????????????'token':?token.key,
????????????'message':?'企業(yè)微信登錄成功',
????????})
寫完接口配置一下路由(這里就不重復(fù)了)
然后請求這個get_authorize_url接口,得到一個地址
{
??"message":?"請求成功",
??"code":?200,
??"data":?{
????"url":?"https://open.weixin.qq.com/connect/oauth2/authorize?appid=wx386...&redirect_uri=http%3A%2F%2Fxxx.com&response_type=code&scope=snsapi_base#wechat_redirect"
??}
}
比如我上面寫的應(yīng)用入口地址是http://xxx.com,那么得到的企業(yè)微信登錄地址就是
https://open.weixin.qq.com/connect/oauth2/authorize?appid=wx386...&redirect_uri=http%3A%2F%2Fxxx.com&response_type=code&scope=snsapi_base#wechat_redirect
各個參數(shù)的意義看企業(yè)微信官方文檔就行,我們不用細(xì)究
企業(yè)微信應(yīng)用配置
接下來我們把這個地址設(shè)置成企業(yè)微信應(yīng)用的主頁
如圖

同時還得設(shè)置一下「可信域名」,在同個頁面的最下方「開發(fā)者接口」處,把前端應(yīng)用部署所在的服務(wù)器域名和端口(80就不用)填上去就行~
這樣應(yīng)用配置就好了
前端代碼
前端用的是京東開源的Taro框架,我前一篇文章寫到我終于用上了React,說的就是在Taro開發(fā)里用React+TypeScript,開發(fā)體驗非常好 (除了這個框架有一些讓人無語的坑之外)
前端要實(shí)現(xiàn)的就是從路徑參數(shù)里取出code
我們看到,Taro官方文檔就有關(guān)于路由參數(shù)的處理
所以可以這樣寫來獲取code(函數(shù)式組件寫法)
import?{?getCurrentInstance?}?from?'@tarojs/taro'
let?code?getCurrentInstance().router?.params['code']
然而!這樣在普通頁面跳轉(zhuǎn)是可以的
比如這種形式
http://xxx.com/#/pages/index/index?code=abc
但人家微信登錄回調(diào)跳轉(zhuǎn)的地址形式是這樣
http://xxx.com?code=abc&state=#/pages/index/index
這根本就拿不到code啊 o(′^`)o
所以得自己用js封裝一個
直接上代碼了
//?解析微信redirect_uri地址中的code
export?const?getCodeFromUrl?=?(url:?string)?=>?{
??let?code?=?''
??let?index?=?url.indexOf('?')
??let?paramStr?=?url.substring(index?+?1,?url.length);
??let?params?=?paramStr.split('&')
??params.forEach(element?=>?{
????if?(element.indexOf('code')?>=?0)?{
??????code?=?element.substring(element.indexOf('=')?+?1,?element.length)
????}
??});
??return?code
}
使用的時候
let?code?=?getCodeFromUrl(window.location.href)
就可以拿到code了
code都有了,后面就不用多說了~
參考資料
wechatpy庫文檔:http://docs.wechatpy.org/zh_CN/stable/oauth.html#id4 企業(yè)微信文檔:https://developer.work.weixin.qq.com/document/path/91335 Taro框架文檔:https://taro-docs.jd.com/taro/docs/router
