You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 
flyapps/fir_ser/api/views/login_wx.py

225 lines
10 KiB

import logging
from django.shortcuts import redirect
from rest_framework.response import Response
from rest_framework.views import APIView
from api.models import UserInfo, ThirdWeChatUserInfo, WeChatInfo
from api.utils.modelutils import get_wx_nickname
from api.utils.response import BaseResponse
from api.utils.serializer import UserInfoSerializer, UserInfoWeiXinSerializer
from api.utils.utils import set_user_token
from common.base.baseutils import get_real_ip_address, WeixinLoginUid
from common.cache.storage import WxLoginBindCache
from common.core.auth import ExpiringTokenAuthentication
from common.core.sysconfig import Config
from common.core.throttle import VisitRegister1Throttle, VisitRegister2Throttle
from common.libs.mp.wechat import make_wx_login_qrcode, show_qrcode_url, WxWebLogin, WxTemplateMsg
from common.utils.caches import set_wx_ticket_login_info_cache, get_wx_ticket_login_info_cache
from common.utils.pending import get_pending_result
from common.utils.token import verify_token, generate_alphanumeric_token_of_length
logger = logging.getLogger(__name__)
def wx_qr_code_response(ret, code, qr_info, ip_addr):
if code:
logger.info(f"微信登录码获取成功, {qr_info}")
errmsg = qr_info.get('errmsg')
if errmsg:
ret.code = 1003
ret.msg = "微信登录码获取失败,请稍后"
else:
ticket = qr_info.get('ticket')
if ticket:
set_wx_ticket_login_info_cache(ticket, {'ip_addr': ip_addr})
ret.data = {'qr': show_qrcode_url(ticket), 'ticket': ticket}
else:
ret.code = 1003
ret.msg = "微信登录码获取失败,请稍后"
return Response(ret.dict)
class WeChatLoginView(APIView):
throttle_classes = [VisitRegister1Throttle, VisitRegister2Throttle]
def get(self, request):
ret = BaseResponse()
if Config.LOGIN.get("login_type").get('third', '').get('wxp'):
unique_key = request.query_params.get('unique_key')
if unique_key:
cache_obj = WxLoginBindCache(unique_key)
cache_data = cache_obj.get_storage_cache()
if cache_data:
code, qr_info = cache_data
else:
code, qr_info = cache_data = make_wx_login_qrcode()
cache_obj.set_storage_cache(cache_data, qr_info.get('expire_seconds', 600))
return wx_qr_code_response(ret, code, qr_info, get_real_ip_address(request))
return Response(ret.dict)
def put(self, request):
ret = BaseResponse()
data = request.data
token = data.get('token')
uid = data.get('uid')
wid = data.get('wid')
if token and uid and wid:
uid = WeixinLoginUid().get_decrypt_uid(uid)
wid = WeixinLoginUid().get_decrypt_uid(wid)
if verify_token(token, uid, True):
user = UserInfo.objects.filter(uid=uid).first()
if user and user.is_active:
wx_user_obj = ThirdWeChatUserInfo.objects.filter(weixin__openid=wid, enable_login=True,
user_id=user).first()
if wx_user_obj:
key, user_info = set_user_token(user, request)
serializer = UserInfoSerializer(user_info)
data = serializer.data
ret.userinfo = data
ret.token = key
ret.msg = "验证成功!"
WxTemplateMsg(wid, get_wx_nickname(wid)).login_success_msg(user.first_name)
else:
ret.msg = "微信状态异常,请重新登录"
ret.code = 1006
else:
ret.msg = "用户被禁用,请更换其他用户登录"
ret.code = 1005
else:
ret.msg = "校验失败,请重新登录"
ret.code = 1006
else:
ret.msg = "参数异常,请重新登录"
ret.code = 1006
return Response(ret.dict)
class WeChatBindView(APIView):
authentication_classes = [ExpiringTokenAuthentication, ]
throttle_classes = [VisitRegister1Throttle, VisitRegister2Throttle]
def post(self, request):
ret = BaseResponse()
uid = request.user.uid
unique_key = request.data.get('unique_key')
w_type = request.data.get('w_type', 'xxxx')
if unique_key:
cache_obj = WxLoginBindCache(unique_key)
cache_data = cache_obj.get_storage_cache()
if cache_data:
code, qr_info = cache_data
else:
code, qr_info = cache_data = make_wx_login_qrcode(f"web.bind.{uid}.{w_type}")
cache_obj.set_storage_cache(cache_data, qr_info.get('expire_seconds', 600))
return wx_qr_code_response(ret, code, qr_info, get_real_ip_address(request))
return Response(ret.dict)
def expect_func(result, *args, **kwargs):
return result and result.get('pk')
class WeChatLoginCheckView(APIView):
def post(self, request):
ret = BaseResponse()
if not Config.LOGIN.get("login_type").get('third', '').get('wxp'):
return Response(ret.dict)
ticket = request.data.get("ticket")
unique_key = request.data.get("unique_key", ticket)
if ticket and unique_key:
status, result = get_pending_result(get_wx_ticket_login_info_cache, expect_func, ticket=ticket,
locker_key=ticket, unique_key=unique_key, run_func_count=1)
if status:
if result.get('err_msg'):
ret.msg = result.get('err_msg')
ret.code = 1004
return Response(ret.dict)
wx_ticket_data = result.get('data', {})
if wx_ticket_data.get('pk', -1) == -1:
ret.msg = "还未绑定用户,请通过手机或者邮箱登录账户之后进行绑定"
ret.code = 1005
else:
ids = wx_ticket_data.get('ids', [])
w_type = wx_ticket_data.get('w_type', '')
to_user = wx_ticket_data.get('to_user', '')
if ids:
user_queryset = UserInfo.objects.filter(pk__in=ids, is_active=True).all()
if user_queryset:
ret.data = UserInfoWeiXinSerializer(user_queryset, many=True,
context={'ticket': ticket}).data
ret.wid = WeixinLoginUid().get_encrypt_uid(to_user)
ret.code = 2000
return Response(ret.dict)
user = UserInfo.objects.filter(pk=wx_ticket_data['pk']).first()
if user.is_active:
if to_user and w_type:
ret.data = {'uid': user.uid, 'to_user': to_user, 'w_type': w_type}
else:
wx_obj = ThirdWeChatUserInfo.objects.filter(user_id=user, weixin__openid=to_user,
enable_login=True).filter()
if not wx_obj:
ret.msg = "还未绑定用户,请通过手机或者邮箱登录账户之后进行绑定"
ret.code = 1005
else:
key, user_info = set_user_token(user, request)
serializer = UserInfoSerializer(user_info)
data = serializer.data
ret.userinfo = data
ret.token = key
ret.msg = "验证成功!"
else:
ret.msg = "用户被禁用"
ret.code = 1005
else:
ret.code = 1006
else:
ret.code = 1006
return Response(ret.dict)
class WeChatWebLoginView(APIView):
throttle_classes = [VisitRegister1Throttle, VisitRegister2Throttle]
def get(self, request):
wx_login_obj = WxWebLogin()
ret = BaseResponse()
code = request.query_params.get('code')
if code:
state = request.query_params.get('state', 'FLYAPPS')
wx_login_obj.get_wx_token(code)
wx_user_info = wx_login_obj.get_user_info()
logger.info(f'{wx_user_info}')
wx_user_info = {
'openid': wx_user_info.get('openid'),
'nickname': wx_user_info.get('nickname'),
'sex': wx_user_info.get('sex'),
'head_img_url': wx_user_info.get('headimgurl', ''),
'address': f"{wx_user_info.get('country')}-{wx_user_info.get('province')}-{wx_user_info.get('city')}",
}
logger.info(f'{wx_user_info}')
WeChatInfo.objects.filter(openid=wx_user_info.get('openid')).update(**wx_user_info)
info = WxLoginBindCache(state).get_storage_cache()
if info and isinstance(info, dict):
info.update({'w_type': 'web', 'to_user': wx_user_info.get('openid')})
set_wx_ticket_login_info_cache(state, info)
return redirect(Config.WEB_DOMAIN)
return Response(ret.dict)
class WeChatWebSyncView(APIView):
authentication_classes = [ExpiringTokenAuthentication, ]
throttle_classes = [VisitRegister1Throttle, VisitRegister2Throttle]
def get(self, request):
logger.error(request.query_params)
wx_login_obj = WxWebLogin()
ret = BaseResponse()
ticket = generate_alphanumeric_token_of_length(32)
WxLoginBindCache(ticket).set_storage_cache({'ip_addr': get_real_ip_address(request), 'pk': request.user.pk})
ret.data = wx_login_obj.make_auth_uri(ticket)
ret.ticket = ticket
return Response(ret.dict)