Browse Source

企业微信登录

peng 2 years ago
parent
commit
cda6094ac1
4 changed files with 409 additions and 6 deletions
  1. 4 3
      VSeesResourceWeb/urls.py
  2. 245 1
      background/Object.py
  3. 14 0
      background/models.py
  4. 146 2
      background/views.py

+ 4 - 3
VSeesResourceWeb/urls.py

@@ -14,10 +14,10 @@ Including another URLconf
     2. Add a URL to urlpatterns:  path('blog/', include('blog.urls'))
 """
 from django.conf.urls import url
-from django.contrib import admin
-from django.urls import path, include
+from django.urls import path, include, re_path
 from rest_framework import routers
-from background.views import ProductInfoSet, VideoInfoSet, QuickStartInfoSet, UpgradeFirmwareInfoSet, GetUploadUrlView
+from background.views import ProductInfoSet, VideoInfoSet, QuickStartInfoSet, UpgradeFirmwareInfoSet, GetUploadUrlView, \
+    WechatLoginView
 
 router = routers.DefaultRouter()
 router.register(r'productInfo', ProductInfoSet)
@@ -28,5 +28,6 @@ router.register(r'upgradeFirmwareInfo', UpgradeFirmwareInfoSet)
 urlpatterns = [
     # path('admin/', admin.site.urls),
     path('getUploadUrl/', GetUploadUrlView.as_view()),
+    re_path(r'^vsees/(?P<operation>.*)', WechatLoginView.as_view()),
     url(r'^', include(router.urls)),
 ]

+ 245 - 1
background/Object.py

@@ -6,13 +6,24 @@
 @Email   : zhangdongming@asj6.wecom.work
 @Software: PyCharm
 """
+import time
 import traceback
-
+import redis
 import boto3
 import botocore
 from boto3.session import Session
 from botocore import client
 from botocore.exceptions import ClientError
+import jwt
+import datetime
+
+SERVER_HOST = 'backendserver.5tgle2.0001.usw1.cache.amazonaws.com'  # 国外节点
+OAUTH_ACCESS_TOKEN_SECRET = 'a+jbgnw%@1%zy^=@dn62%'
+OAUTH_REFRESH_TOKEN_SECRET = 'r+jbgnw%@1%zy^=@dn62%'
+# access_token超时
+OAUTH_ACCESS_TOKEN_TIME = datetime.timedelta(days=30)
+# refresh_token超时
+OAUTH_REFRESH_TOKEN_TIME = datetime.timedelta(days=30)
 
 
 class AmazonS3Util:
@@ -237,3 +248,236 @@ class AmazonS3Util:
             return obj['Contents']
         except Exception as e:
             return []
+
+
+class RedisObject:
+
+    def __init__(self, db=0):
+        self.POOL = redis.ConnectionPool(host=SERVER_HOST, port=6379, db=db)
+        self.CONN = redis.Redis(connection_pool=self.POOL)
+
+    def set_data(self, key, val, expire=0):
+        try:
+            self.CONN.set(key, val)
+            if expire > 0:
+                self.CONN.expire(key, expire)
+        except Exception as e:
+            return False
+        else:
+            return True
+
+    def get_data(self, key):
+        try:
+            val = self.CONN.get(key)
+        except Exception as e:
+            print(repr(e))
+            return False
+        else:
+            if val:
+                return val.decode('utf-8')
+            else:
+                return False
+
+    def del_data(self, key):
+        try:
+            val = self.CONN.delete(key)
+        except Exception as e:
+            print(repr(e))
+            return False
+        else:
+            return True
+
+    def get_size(self):
+        return self.CONN.dbsize()
+
+    # 向列表插入数据
+    def rpush(self, name, val):
+        self.CONN.rpush(name, val)
+
+    def lpop(self, name):
+        val = self.CONN.lpop(name)
+        if val:
+            return val.decode('utf-8')
+        else:
+            return False
+
+    # 获取列表长度
+    def llen(self, name):
+        return self.CONN.llen(name=name)
+
+    # 获取列表所有数据
+    def lrange(self, name, start, end):
+        return self.CONN.lrange(name, start, end)
+
+    # 删除列表指定数据
+    def lrem(self, name, num, value):
+        """
+        num:列表方向,删除个数(0:所有)
+        value:删除的值
+        """
+        return self.CONN.lrem(name, num, value)
+
+    def get_ttl(self, key):
+        ttl = self.CONN.ttl(key)
+        if ttl:
+            return ttl
+        else:
+            return 0
+
+    def get_keys(self, key):
+        keys = self.CONN.keys(key)
+        if keys:
+            return keys
+        else:
+            return False
+
+    def set_ex_data(self, key, val, expire=0):
+        try:
+            self.CONN.setex(name=key, time=expire, value=val)
+        except Exception as e:
+            return False
+        else:
+            return True
+
+    def set_hash_data(self, key, kwargs):
+        self.CONN.hmset(key, kwargs)
+
+    def get_hash_data(self, key, file):
+        return self.CONN.hmget(key, file)
+
+    def get_all_hash_data(self, key):
+        return self.CONN.hgetall(key)
+
+
+class TokenObject:
+
+    def __init__(self, token=None, returntpye='currency'):
+        if token == 'local':
+            token = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VySUQiOiIxNTg0MzUxODk2MjgyMTM4MDAxMzgwMDAiLCJsYW5nIjoiZW4iLCJ1c2VyIjoiMTM2ODAzMTc1OTYiLCJtX2NvZGUiOiIxMjM0MTMyNDMyMTQiLCJleHAiOjE1ODcyNzcwNjB9.c0LV_XyxwbzUlYqMJqx7vw9f19Jv-0kGnUHuu_go-mo'
+        if token == 'test':
+            token = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyIjoiMTM4MDAxMzgwMDEiLCJleHAiOjE1Njk5OTg4OTYsInVzZXJJRCI6IjE1MTU2NDI2MjMzNzkzOTUxMzgwMDEzODAwMSIsImxhbmciOiJlbiIsIm1fY29kZSI6IjEyMzQxMzI0MzIxNCJ9.VAQtT9AbCCfXcrNj9DL5cvVasMDoI7AP8ptgU1GoMu8'
+        self.token = token
+        self.lang = None
+        self.userID = None
+        self.user = ''
+        self.code = 0
+        self.valid()
+        self.returntpye = returntpye
+
+    def valid(self):
+        if self.token is None:
+            self.code = 309
+            return
+        try:
+            self.token = self.token.replace("Bearer ", "")
+
+            res = jwt.decode(self.token, OAUTH_ACCESS_TOKEN_SECRET, algorithms='HS256')
+            self.userID = res.get('userID', None)
+            self.lang = res.get('lang', None)
+            self.user = res.get('user', '')
+            # 刷新登录时间
+            # if self.userID:
+            #     print(self.user)
+            #     redisObj = RedisObject(db=3)
+            #     redisObj.set_data(key=self.userID, val=self.user, expire=300)
+
+        except jwt.ExpiredSignatureError as e:
+            self.code = 309
+            return
+        except Exception as e:
+            self.code = 309
+            return
+        else:
+            if not self.userID:
+                self.code = 309
+                return
+            else:
+                if self.userID:
+                    self.code = 0
+                    return res
+                else:
+                    self.code = 309
+                    return
+
+    def generate(self, data=None):
+        if data is None:
+            data = {}
+        try:
+            access_expire = int(OAUTH_ACCESS_TOKEN_TIME.total_seconds())
+            refresh_expire = int(OAUTH_REFRESH_TOKEN_TIME.total_seconds())
+            now_stamp = int(time.time())
+            access_data = data
+            refresh_data = data
+            access_data['exp'] = access_expire + now_stamp
+            refresh_data['exp'] = refresh_expire + now_stamp
+            access_token = jwt.encode(access_data,
+                                      OAUTH_ACCESS_TOKEN_SECRET,
+                                      algorithm='HS256')
+            refresh_token = jwt.encode(
+                refresh_data,
+                OAUTH_REFRESH_TOKEN_SECRET,
+                algorithm='HS256')
+
+            res = {
+                'access_token': access_token,
+                'access_expire': access_expire,
+                'refresh_expire': refresh_expire,
+                'refresh_token': refresh_token,
+            }
+
+            if self.returntpye == 'pc':
+                res = {
+                    'token': access_token,
+                    'access_expire': access_expire,
+                    'refresh_expire': refresh_expire,
+                    'refresh_token': refresh_token,
+                }
+
+        except Exception as e:
+            self.code = 309
+            print(repr(e))
+        else:
+            self.code = 0
+            return res
+
+    def encryption(self, data=None):
+        if data is None:
+            data = {}
+        try:
+            access_expire = int(OAUTH_ACCESS_TOKEN_TIME.total_seconds())
+            refresh_expire = int(OAUTH_REFRESH_TOKEN_TIME.total_seconds())
+            now_stamp = int(time.time())
+            access_data = data
+            refresh_data = data
+            access_data['exp'] = access_expire + now_stamp
+            refresh_data['exp'] = refresh_expire + now_stamp
+            access_token = jwt.encode(access_data,
+                                      OAUTH_ACCESS_TOKEN_SECRET,
+                                      algorithm='HS256')
+            return access_token
+        except Exception as e:
+            self.code = 309
+            print(repr(e))
+
+    def refresh(self):
+        if not self.token:
+            self.code = 309
+            return
+        try:
+            res = jwt.decode(self.token, OAUTH_REFRESH_TOKEN_SECRET, algorithms='HS256')
+        except jwt.ExpiredSignatureError as e:
+            print('过期')
+            print(repr(e))
+            self.code = 309
+        except Exception as e:
+            self.code = 309
+            print(repr(e))
+        else:
+            self.code = 0
+            userID = res.get('userID', '')
+            user = res.get('user', '')
+            lang = self.lang
+            self.userID = userID
+            self.user = user
+            refreshRes = self.generate(data={'userID': userID, 'lang': lang, 'user': user})
+            return refreshRes

+ 14 - 0
background/models.py

@@ -2,6 +2,20 @@
 from django.db import models
 
 
+class WechatUserInfo(models.Model):
+    user_id = models.IntegerField(primary_key=True, verbose_name=u'企业用户ID', unique=True)
+    name = models.CharField(blank=True, max_length=32, verbose_name=u'名字')
+    position = models.CharField(blank=True, max_length=64, verbose_name=u'岗位')
+    status = models.SmallIntegerField(default=0, verbose_name='用户状态')  # 1:已激活,2:已禁用,4:未激活,5:退出企业
+    add_time = models.IntegerField(default=0, verbose_name='创建时间')
+    upd_time = models.IntegerField(default=0, verbose_name='修改时间')
+
+    class Meta:
+        db_table = 'wechat_user_info'
+        verbose_name = '企业用户信息'
+        verbose_name_plural = verbose_name
+
+
 class ProductInfo(models.Model):
     id = models.AutoField(primary_key=True, verbose_name='主键')
     product_name = models.CharField(default='', max_length=32, verbose_name='产品名称')

+ 146 - 2
background/views.py

@@ -1,11 +1,16 @@
 # Create your views here.
+import hashlib
+import time
+import uuid
+
+import requests
 from rest_framework.views import APIView
 from rest_framework.viewsets import ModelViewSet
 
-from background.Object import AmazonS3Util
+from background.Object import AmazonS3Util, RedisObject, TokenObject
 from background.serializers import ProductInfoSerializer, VideoInSerializer, QuickStartInfoSerializer, \
     UpgradeFirmwareInfoSerializer
-from background.models import ProductInfo, VideoInfo, QuickStartInfo, UpgradeFirmwareInfo
+from background.models import ProductInfo, VideoInfo, QuickStartInfo, UpgradeFirmwareInfo, WechatUserInfo
 from rest_framework.response import Response
 
 
@@ -54,3 +59,142 @@ class GetUploadUrlView(APIView):
         except Exception as e:
             return Response(
                 {'code': 500, 'result': {'error_line:{}, error_msg:{}'.format(e.__traceback__.tb_lineno, repr(e))}})
+
+
+class WechatLoginView(APIView):
+    def get(self, request, *args, **kwargs):
+        request.encoding = 'utf-8'
+        operation = kwargs.get('operation')
+        return self.validation(request.GET, operation, request)
+
+    def post(self, request, *args, **kwargs):
+        request.encoding = 'utf-8'
+        operation = kwargs.get('operation')
+        return self.validation(request.POST, operation, request)
+
+    def validation(self, request_dict, operation, request):
+        if operation == 'get-state':  # 获取state值
+            return self.get_state()
+        elif operation == 'get-user':  # 获取用户
+            return self.get_user(request_dict)
+        else:
+            return Response({'code': 414, 'result': {'error_msg': '请求路径有误'}})
+
+    @staticmethod
+    def get_state():
+        """
+        获取state
+        @return: response
+        """
+        nwo_time = time.time()
+        redis_obj = RedisObject()
+        try:
+            state = hashlib.md5((str(uuid.uuid1()) + str(nwo_time)).encode('utf-8')).hexdigest()
+            state_statue = redis_obj.set_ex_data(state, 0, 300)  # redis记录state
+            if state_statue:
+                return Response({'code': 0, 'result': {'state': state}})
+            else:
+                return Response({'code': 120, 'result': {'error_msg': '获取status失败'}})
+        except Exception as e:
+            return Response(
+                {'code': 500, 'result': {'error_line:{}, error_msg:{}'.format(e.__traceback__.tb_lineno, repr(e))}})
+
+    @classmethod
+    def get_user(cls, request_dict):
+        """
+        获取用户信息
+        @request_dict code:唯一标识
+        @request_dict state:唯一标识
+        return:
+        """
+        code = request_dict.get('code', None)
+        state = request_dict.get('state', None)
+        if not all([code, state]):
+            return Response({'code': 444, 'result': {'error_msg': '缺少参数'}})
+        # 验证state,获取token
+        access_token = cls.get_access_token(state)
+        if not access_token:
+            return Response({'code': 120, 'result': {'error_msg': '获取token失败'}})
+        data = {
+            'access_token': access_token,
+            'code': code
+        }
+        try:
+            #  获取用户id
+            get_userid_url = 'https://qyapi.weixin.qq.com/cgi-bin/auth/getuserinfo'
+            response = requests.get(get_userid_url, params=data)
+            data = response.json()
+            user_id = data.get("userid")
+            if user_id:
+                user_name = cls.add_or_update_user_info(access_token, user_id)
+                if not user_name:
+                    return Response({'code': 120, 'result': {'error_msg': '登录失败'}})
+                token_obj = TokenObject()
+                token = token_obj.generate(data={'userID': user_id, 'user': user_name})
+                return Response({'code': 0, 'result': {'token': token}})
+            else:
+                errcode = data.get('errcode')
+                errmsg = data.get('errmsg')
+                return Response({'code': errcode, 'result': {'error_msg': errmsg}})
+        except Exception as e:
+            return Response(
+                {'code': 500, 'result': {'error_line:{}, error_msg:{}'.format(e.__traceback__.tb_lineno, repr(e))}})
+
+    @classmethod
+    def get_access_token(cls, state):
+        redis_client = RedisObject()
+        state_val = redis_client.get_data(state)
+        #  验证state
+        if state_val:
+            redis_client.del_data(state)
+        else:
+            return False
+        access_token = redis_client.get_data(key='enterprise_wechat_access_token')
+        if access_token:
+            return access_token
+        data = {
+            'corpid': 'ww467ec1685e8262e6',
+            'corpsecret': 'IeUoaQ-0hEhEduCQq1zyfVXjfeZpMsThK1nklszRzUY'
+        }
+        #  获取access_token,redis中不存在该值时重新请求获取access_token(有效时长两小时)
+        token_url = 'https://qyapi.weixin.qq.com/cgi-bin/gettoken'
+        token_response = requests.get(token_url, params=data)
+        data = token_response.json()
+        if data.get('errcode') == 0:
+            access_token = data['access_token']
+            redis_client.set_data('enterprise_wechat_access_token', access_token)
+            return access_token
+        else:
+            return False
+
+    @classmethod
+    def add_or_update_user_info(cls, access_token, user_id):
+        now_time = int(time.time())
+        data = {
+            'access_token': access_token,
+            'userid': user_id
+        }
+        #  获取用户信息
+        token_url = 'https://qyapi.weixin.qq.com/cgi-bin/user/get'
+        response = requests.get(token_url, params=data)
+        data = response.json()
+        wechat_user_qs = WechatUserInfo.objects.filter(user_id=user_id)
+        if data.get('errcode') == 0:
+            url_data = {
+                'name': data.get('name'),
+                'position': data.get('position'),
+                'status': data.get('status'),
+                'add_time': now_time,
+                'upd_time': now_time
+            }
+            if not wechat_user_qs.exists():
+                url_data['user_id'] = user_id
+                WechatUserInfo.objects.create(**url_data)
+            else:
+                wechat_user_qs.update(url_data)
+            if data.get('status') == 1:
+                return data.get('name')
+            else:
+                return False
+        else:
+            return False