Files
sixGuoDjango/django_web_微信开放平台应用用户登陆/接收微信的code回调.py
T
2026-08-02 14:07:04 +08:00

134 lines
6.1 KiB
Python

import threading
from datetime import datetime, timedelta
from functools import wraps
from pathlib import Path
from urllib.parse import urlencode
from zoneinfo import ZoneInfo
import orjson
import pydash
import requests
from Crypto.PublicKey import RSA
from django.conf import settings
from django.http import HttpResponseRedirect
from jwt import JWT, jwk_from_pem
from jwt.utils import get_int_from_datetime
from rest_framework.decorators import action
from rest_framework.request import Request
from rest_framework.viewsets import ViewSet
from wechat_token.token数据库 import weitoken
def sync_lock_线程锁(lock):
def decorator(fn):
@wraps(fn)
def wrapper(*args, **kwargs):
with lock:
return fn(*args, **kwargs)
return wrapper
return decorator
class AllowMyAppRedirect(HttpResponseRedirect):
allowed_schemes = ["http", "https", "myapp"]
class 接收微信的code回调ViewSets(ViewSet):
lock = threading.Lock()
private_key_pem_私钥 = Path(settings.BASE_DIR).joinpath("django_jwt_token/private.pem").read_bytes()
def jwt_生成token(self, openid, uniond):
# 读取私钥的 bytes字符串
# 创建一个 JWT对象
jwt对象实例 = JWT() # 创建对象
# 创建 payload
message = {
"openid": openid,
"uniond": uniond,
'iat': get_int_from_datetime(datetime.now(tz=ZoneInfo(key="utc"))), # 生成jwt-token的时间
'exp': get_int_from_datetime(datetime.now(tz=ZoneInfo(key="utc")) + timedelta(hours=1)), # 多长时间过期
}
# 获取私钥对象 (并且要私钥的密码)
私钥对象 = RSA.import_key(extern_key=self.private_key_pem_私钥, passphrase=settings.SECRET_KEY).export_key()
signing_key = jwk_from_pem(pem_content=私钥对象, )
token = jwt对象实例.encode(payload=message, key=signing_key, alg="RS256")
return token
def get网站授权access_token(self, code, state):
uri = "https://api.weixin.qq.com/sns/oauth2/access_token"
postData = requests.post(url=uri, params={
"appid": "wx6c9d4541e0285d02",
"secret": "bb87178b80e23f2fc96b688577dafca4",
"code": code,
"grant_type": "authorization_code"
}).json()
access_token = pydash.get(obj=postData, path="access_token")
expires_in = pydash.get(obj=postData, path="expires_in")
refresh_token = pydash.get(obj=postData, path="refresh_token")
openid = pydash.get(obj=postData, path="openid")
scope = pydash.get(obj=postData, path="scope")
unionid = pydash.get(obj=postData, path="unionid")
return postData
def get获取用户个人信息(self, code, state):
uri = f"https://api.weixin.qq.com/sns/userinfo"
token, is创建 = weitoken.objects.update_or_create(token_name="web_token")
if is创建:
wx_access_token_dict = self.get网站授权access_token(code=code, state=state)
token.token_value = pydash.get(obj=wx_access_token_dict, path="access_token")
token.save()
access_token = pydash.get(obj=wx_access_token_dict, path="access_token")
openid = pydash.get(obj=wx_access_token_dict, path="openid")
getData = requests.get(url=uri, params={"access_token": access_token, "openid": openid})
res = orjson.loads(getData.content.decode(encoding="utf-8"))
return res
else:
time创建时间 = token.updateTime.timestamp() # 更新时间的时间戳
current_时间戳 = get_int_from_datetime(value=datetime.now())
if current_时间戳 - time创建时间 > 3600:
# 时间过期时,需要重新请求 拿到新的 access_token
wx_access_token_dict = self.get网站授权access_token(code=code, state=state)
# 更新token的值
token.token_value = pydash.get(obj=wx_access_token_dict, path="access_token")
token.save()
access_token = pydash.get(obj=wx_access_token_dict, path="access_token")
openid = pydash.get(obj=wx_access_token_dict, path="openid")
getData = requests.get(url=uri, params={"access_token": access_token, "openid": openid})
res = orjson.loads(getData.content.decode(encoding="utf-8"))
return res
else:
wx_access_token_dict = self.get网站授权access_token(code=code, state=state)
# 更新token的值
token.token_value = pydash.get(obj=wx_access_token_dict, path="access_token")
token.save()
access_token = pydash.get(obj=wx_access_token_dict, path="access_token")
openid = pydash.get(obj=wx_access_token_dict, path="openid")
getData = requests.get(url=uri, params={"access_token": access_token, "openid": openid})
res = orjson.loads(getData.content.decode(encoding="utf-8"))
return res
@action(detail=False, methods=["get", ], url_path="get_code", )
# @sync_lock_线程锁( lock=lock )
def get_code(self, request: Request):
"""
前端,带着code的get请求,在这里拿到code,获取登陆用户的信息,
重点: 通过回调,前端,(处理业务逻辑) 由于我这里使用的是Mac桌面版本.
:param request:
:return:
"""
code = request.query_params.get(key="code", default=None)
state = request.data.get("state", None)
user_info_用户信息 = self.get获取用户个人信息(code=code, state=state)
openid = pydash.get(obj=user_info_用户信息, path="openid")
unionid = pydash.get(obj=user_info_用户信息, path="unionid")
print("为什么没有值了呢", openid, unionid)
token = self.jwt_生成token(openid=openid, uniond=unionid)
setData = pydash.set_(obj=user_info_用户信息, path="token", value=token)
query_string = urlencode(setData, )
uri = f"myapp://open/home?{query_string}"
return AllowMyAppRedirect(redirect_to=uri)