一般情况下,在公众号里的菜单或绑定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)
到了登录页面,就是短信验证,手机注册了。下一节继续腾讯云手机验证。