前言
還是最近在做的一個小項目,后端用的是Django搭配RestFramework做接口,前端第一次嘗試用京東開源的Taro框架來做多端(目前需要做用於企業微信的H5端和微信小程序)
本文記錄一下企業微信登錄的流程,上周看文檔看得頭暈暈的,其實很簡單,封裝好了就幾行代碼的事~
兩種方式
- 一種是先拼接好登錄要用的地址
authorize_url
,回調地址設置成h5應用的網頁入口,然后把authorize_url
設置為企業微信里的應用主頁就行,然后直接提取鏈接里的code - 另一種是在應用里拼接
authorize_url
地址,回調地址同樣設置成h5應用的網頁入口,然后應用里去請求authorize_url
,然后提取鏈接里的code用來登錄就行
說是兩種,其實流程都是一樣的,只不過第一種少去了前端拼接authorize_url
以及首次請求的操作,為了方便起見,本文推薦使用第一種
思路
假設前端地址是http://xxx.com
,那么我們用后端生成的企業微信登錄地址中會把前端地址作為回調地址傳入,在企業微信中訪問登錄地址之后,回跳轉到我們的前端地址,並在路徑中附上參數code,形式如下:
http://xxx.com?code=dkwawen123j13bk1
所以前端要做的就是拿到這串code,並提交給后端,讓后端拿code去微信服務器換用戶信息,就這樣~
后端代碼
企業微信登錄的接口已經集成在我的「DjangoStarter」項目模板中,可以直接食用~
后端使用的是wechatpy這個庫,非常好用,封裝了微信開發的常用功能~
下面寫一下兩個關鍵的方法
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):
"""微信企業號相關認證服務"""
client = WeChatClient(
settings.WECHAT_WORK_CONFIG['CORP_ID'],
settings.WECHAT_WORK_CONFIG['SECRET'],
)
@swagger_auto_schema(operation_summary='獲取微信企業號登錄鏈接')
@action(detail=False)
def get_authorize_url(self, request):
return Response({
# todo 這里要寫上前端應用入口地址
'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='從微信企業號服務器獲取到的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登錄狀態
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': '企業微信登錄成功',
})
寫完接口配置一下路由(這里就不重復了)
然后請求這個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"
}
}
比如我上面寫的應用入口地址是http://xxx.com
,那么得到的企業微信登錄地址就是
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
各個參數的意義看企業微信官方文檔就行,我們不用細究
企業微信應用配置
接下來我們把這個地址設置成企業微信應用的主頁
如圖
同時還得設置一下「可信域名」,在同個頁面的最下方「開發者接口」處,把前端應用部署所在的服務器域名和端口(80就不用)填上去就行~
這樣應用配置就好了
前端代碼
前端用的是京東開源的Taro框架,我前一篇文章寫到我終於用上了React,說的就是在Taro開發里用React+TypeScript,開發體驗非常好 (除了這個框架有一些讓人無語的坑之外)
前端要實現的就是從路徑參數里取出code
我們看到,Taro官方文檔就有關於路由參數的處理
所以可以這樣寫來獲取code(函數式組件寫法)
import { getCurrentInstance } from '@tarojs/taro'
let code getCurrentInstance().router?.params['code']
然而!這樣在普通頁面跳轉是可以的
比如這種形式
http://xxx.com/#/pages/index/index?code=abc
但人家微信登錄回調跳轉的地址形式是這樣
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都有了,后面就不用多說了~