首页 > 技术文章 > 0039 微信公众平台开发 (08 获取网页授权)

dorian 2020-03-09 09:51 原文

  一般情况下,在公众号里的菜单或绑定url的文字图片等,就是点击需要跳转到我们编写的网页上去的时候,直接绑定接口的外网访问地址就可以了。也就是说,在浏览器怎么访问,在微信里还是怎么访问。

  但在微信里,如果没有域名,会弹出提示页面,要求用户绑定域名。

  微信的网页授权登录,主要是针对登录页面,要验证用户身份。而这不是我们关心的,因为用户身份需要我们自己写程序去验证,如手机号验证。这个功能形同鸡肋。但微信网页授权的另一个功能是,只要这个网页通过了微信授权,就可以获取当前用户的所有资料,包括openid。

  openid是公众号用户的唯一标识,把openid和手机号一起存在用户信息模型中,这样就可以随时获取用户信息了。

  这种情况一般在注册或绑定手机号的页面使用。  

  网页授权的前提是:在接口权限表中设置网页授权获取用户信息中去修改服务器IP。测试账号,直接进入后下拉,正式账号在公众号首页/开发/接口权限中。

  注:这里一般填服务器IP或域名,表示这个IP下所有url都是被微信允许授权的。

  根据微信官网文档《微信网页开发/网页授权》,网页授权分为四步,我们把微信网页授权和工程授权结合起来,全面演绎登录授权的业务逻辑。

1 准备工作

  准备两个网页,一是访问主页,二是登录页面。

1.1 登录页面,Applications/Organizations/Templates/login.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1>登录页面</h1>
</body>
</html>

1.2 登录视图 Applications/Organizations/views/Login.py

from django.shortcuts import render
from rest_framework.views import APIView


class Login(APIView):
    @classmethod
    def get(cls, request):
        """
        【功能描述】主要用于示例展示</br>
        【返回参数】返回用户请求的网页</br>

        """
        return render(request, 'login.html')

1.3 用户首页页面Applications/Organizations/Templates/user-home.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1>用户首页</h1>
</body>
</html>

1.4 用户首页视图Applications/Organizations/views/UserHome.py

from django.shortcuts import render
from rest_framework.views import APIView
from GeneralTools.AuthToken import decorate
from django.utils.decorators import method_decorator


@method_decorator(decorate, name='get')
class UserHome(APIView):

    @classmethod
    def get(cls, request):
        """
        【功能描述】用户主页</br>
        【返回参数】返回用户请求的网页</br>

        """
        return render(request, 'user-home.html')

2 公共方法

  登录验证需要四个公共方法

  getToken:获取access_token,用户绑定手机号成功后,返回用户一个access_token,以后,用户携带access_token来访问工程中所有接口。

  checkToken:检查access_token是否有效(被篡改或失效),如果有效,则把手机号存入session中,以便用户使用页面时,可以根据手机号获取用户权限或用户信息。

  get_WeChatOAuth:拼接成微信授权回调url,用于微信网页授权时调用。

  decorate:装饰器,用于对所有需要授权的网页进行认证。如果认证成功,则直接返回所访问的网页,如果认证失败,有两种情况:微信浏览器访问,则返回一个授权回调地址;其它浏览器访问,则直接返回需要访问的页面。

  在GeneralTools下创建文件,名为:AuthToken.py,内容如下:

from django.shortcuts import redirect
from itsdangerous import TimedJSONWebSignatureSerializer as TJWSSerializer
from itsdangerous import BadData
from TongHeng2 import settings
from . import Constents
from rest_framework.response import Response
from rest_framework import status
import logging
from wechatpy.oauth import WeChatOAuth

logger = logging.getLogger('tongheng2')


def getToken(openid, mobile):
    """
    【功能说明】根据用户openid和mobile用于生成access_token
    """
    tjwserializer = TJWSSerializer(
        secret_key=settings.SECRET_KEY,  # 密钥
        salt=Constents.SALT,  # 盐值
        expires_in=Constents.VERIFY_ACCESS_TOKEN_EXPIRES  # 有效期
    )
    access_token = tjwserializer.dumps({'openid': openid, 'mobile': mobile})  # bytes
    access_token = access_token.decode()
    return access_token


def checkToken(token, request):
    """
    【功能说明】检查access_token是否正确
    """
    tjwserializer = TJWSSerializer(
        secret_key=settings.SECRET_KEY,  # 密钥
        salt=Constents.SALT,  # 盐值
        expires_in=Constents.VERIFY_ACCESS_TOKEN_EXPIRES  # 有效期
    )
    try:
        tjwdata = tjwserializer.loads(token)
        # 如果验证成功,则把手机号存入到session里面,以便在页面中可以随时根据mobile获取用户信息和权限。
        mobile = tjwdata['mobile']
        request.session['mobile'] = mobile
        return True
    except BadData as e:
        logger.error(e)
        return False


def get_WeChatOAuth(redirect_uri, state='123', scope='snsapi_userinfo'):
    """
    获取WeChatOAuth对象
    :param redirect_uri: 授权后重定向的回调链接地址, 请使用 urlEncode 对链接进行处理
    :param scope:应用授权作用域,snsapi_base,snsapi_userinfo
    :param state:重定向后会带上state参数,开发者可以填写a-zA-Z0-9的参数值,最多128字节
    :return: WeChatOAuth对象
    """

    return WeChatOAuth(
        app_id=Constents.WECHAT_APPID,
        secret=Constents.WECHAT_APPSECRET,
        redirect_uri=redirect_uri,
        scope=scope,
        state=state
    )


# 装饰器
def decorate(func):
    def wrapper(request, *args, **kwargs):
        # 从用户session中,获取access_token
        access_token = request.session.get('access_token', None)
        if access_token and checkToken(access_token, request):
            # 如果access_token存在,且正确,则直接执行下一步
            return func(request, *args, **kwargs)
        else:
            # 如果access_token不存在,或不正确
            userAgent = str(request.META['HTTP_USER_AGENT'])  # 获取访问浏览器的类型
            if userAgent.find('MicroMessenger') < 0:  # 如果不是微信浏览器,则直接跳转到登录页面
                return redirect('/Organizations/Login/')
            else:  # 如果是微信浏览器,返回微信授权回调地址,前端根据地址,调用login登录页面。
                url = get_WeChatOAuth(Constents.REDIRECT_URI).authorize_url
                return Response(data={'url': url}, status=status.HTTP_201_CREATED)

    return wrapper

3 添加装饰器

  把装饰器添加到需要验证的页面上。

  打开Applicatoins/Organizations/views/UserHome.py

from django.shortcuts import render
from rest_framework.views import APIView
from GeneralTools.AuthToken import decorate
from django.utils.decorators import method_decorator


@method_decorator(decorate, name='get')
class UserHome(APIView):

    @classmethod
    def get(cls, request):
        """
        【功能描述】用户主页</br>
        【返回参数】返回用户请求的网页</br>

        """
        return render(request, 'user-home.html')

 

4 服务器发布工程

  由于微信公众号网页授权必须要有公网IP,故需要在服务器发布。

  发布后在微信中访问,则显示以下页面,而在其它浏览器访问,则直接显示登录页面。

  此时,前端得到了授权回调地址,把这个地址拷贝到微信执行,可看到登录

5 编写登录视图  

  登录视图的思路如下:

  获取code和state:如果code不存在,表示不是微信浏览器访问,则返回一个空的用户信息

  如果code存在,则根据state重新获取wechatOAuth对象

  把code传入wechatOAuth对象,获取access_token

  刷新access_token

  获取用户微信信息,并把这个信息返回前端。.

from django.shortcuts import render
from rest_framework.views import APIView
from GeneralTools.AuthToken import get_WeChatOAuth
from GeneralTools import Constents


class Login(APIView):
    @classmethod
    def get(cls, request):
        """
        【功能描述】主要用于示例展示</br>
        【返回参数】返回用户请求的网页</br>
        """
        code = request.GET.get('code')
        state = request.GET.get('state')
        # 根据state重新获取WeChatOAuth对象,用此处收到的state和之前的state进一步验证url的可靠性
        wechatOAuth = get_WeChatOAuth(Constents.REDIRECT_URI, state)
        if code:
            access_token = wechatOAuth.fetch_access_token(code)
            refresh_token = access_token['refresh_token']
            if not wechatOAuth.check_access_token():
                # 刷新access_token
                wechatOAuth.refresh_access_token(refresh_token)
            user_info = wechatOAuth.get_user_info()
            print(user_info)
        else:
            user_info = {}
        return render(request, 'login.html', context=user_info)

   到了登录页面,就是短信验证,手机注册了。下一节继续腾讯云手机验证。

 

 

 

  

 

推荐阅读