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.
225 lines
10 KiB
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)
|
|
|