import hashlib import threading from datetime import datetime, timedelta from functools import wraps from pathlib import Path from zoneinfo import ZoneInfo from Crypto.PublicKey import RSA from django.conf import settings from django.http import HttpResponse, 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.response import Response from rest_framework.viewsets import ViewSet from wechat_token.token工具包 import sixToken from wechat_数据库.雪花算法.雪花算法工具 import generator def sync_lock_线程锁( lock ): def decorator( fn ): @wraps( fn ) def wrapper( *args, **kwargs ): with lock: return fn( *args, **kwargs ) return wrapper return decorator class 服务号网页授权接口ViewSets( ViewSet ): lock = threading.Lock( ) def jwt_生成token( self, 有效时间_单位小时: int = 1 ): # 读取私钥的 bytes字符串 private_key_pem_私钥 = Path( settings.BASE_DIR ).joinpath( "django_jwt_token/private.pem" ).read_bytes( ) # 创建一个 JWT对象 jwt对象实例 = JWT( ) # 创建对象 # 创建 payload message = { "oenid": "xiaozizi", "uniond": "kladfj", '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=有效时间_单位小时 ) ), # 多长时间过期 } # 获取私钥对象 (并且要私钥的密码) 私钥对象 = RSA.import_key( extern_key=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 @action( detail=False, methods=[ "get", "post", "put", "delete" ], url_path="get_code" ) # @sync_lock_线程锁( lock=lock ) def 获取code接口( self, request: Request ): pass code = request.query_params.get( key="code", default=None ) print( "拿到的code的值是多少了呢?", code ) six_token = self.jwt_生成token( 有效时间_单位小时=24 ) uri = f"http://0.0.0.0:3000/home?six_token={six_token}" # uri = f"https://wechat.sixgou.com?code={code}" return HttpResponseRedirect( redirect_to=uri ) @action( detail=False, methods=[ "get", "post", "put", "delete" ], url_path="msg" ) # @sync_lock_线程锁( lock=lock ) def 响应微信服务器回调Token( self, request: Request ): pass print( request.headers ) signature = request.query_params.get( key="signature", default="" ) timestamp = request.query_params.get( key="timestamp", default="" ) nonce = request.query_params.get( key="nonce", default="" ) echostr = request.query_params.get( key="echostr", default="" ) print( signature, "===================" ) token = "xiaozizi" params = [ token, timestamp, nonce ] params.sort( ) tmp_str = "".join( params ) sig_str = f"{token}{timestamp}{nonce}" res = hashlib.sha1( data=tmp_str.encode( encoding="utf-8" ) ).hexdigest( ) if sig_str == res: print( "判断相等了" ) return HttpResponse( content=echostr ) @action( detail=False, methods=[ "get", "post", "put", "delete" ], url_path="signature" ) # @sync_lock_线程锁( lock=lock ) def signature( self, request: Request ): """ 对网页请求使用 的功能进行授权 如:chooiseImage (在微信环境中,调用用户的相机的功能) 从前端的body,接收到url,然后后端生成随机字符串和时间戳 重点: 这个属性的key的字符,大小写要一模一样 :param request: :return: """ pass url = request.data.get( "url", None ) timestamp = get_int_from_datetime( value=datetime.now( ) ) nonceStr = generator.generate_str( ) jsapi_ticket = sixToken.get_wechat_tick_token( ) sig_str = f"jsapi_ticket={jsapi_ticket}&noncestr={nonceStr}×tamp={timestamp}&url={url}" signature = hashlib.sha1( data=sig_str.encode( encoding="utf-8" ) ).hexdigest( ) return Response( data={ "nonceStr": nonceStr, "timestamp": timestamp, "signature": signature } ) # @action( detail=False, methods=[ "get",], url_path="认证接口文件" ) # @sync_lock_线程锁( lock=lock ) def 认证接口文件( self, request: Request ): pass return HttpResponse( content="kMmcLX8ZO79apUxA" )