django 微信网页授权登陆的实现


Posted in Python onJuly 30, 2019

一、准备工作

0x00 开发前准备

  • 服务号!!!
  • 微信认证。
  • 备案过的域名。
  • 服务器。

 0x01 手动触发dns更新

django 微信网页授权登陆的实现

0x02 配置业务域名

django 微信网页授权登陆的实现 

0x03 将服务器请求转发到本地

修改服务器的 /etc/ssh/sshd_config 加入 GatewayPorts yes

ssh -R 0.0.0.0:80:localhost:8080 user@server_host

二、微信网页授权

0x01 授权流程

用户同意授权,获取 code

想办法让用户页面跳转到微信的授权链接(比如在修饰器中进行跳转):

def get_wx_authorize_url(appid : str, state: str = None):
  if state is None:
    state = "".join([random.choice(string.ascii_letters + string.digits) for _ in range(20)])
  redirect_url = 'your callback url' # 回调链接,在这里面进行用户信息入库的操作
  response_type = 'code'
  scope = 'snsapi_userinfo'
  wx_url = f"https://open.weixin.qq.com/connect/oauth2/authorize?appid={appid}&redirect_uri={redirect_url}&response_type={response_type}&scope={scope}&state={state}#wechat_redirect"
  return wx_url

通过 code 换取 access_tokenopenid

def request_access_token(appid : str, secret : str, code: str):
  secret = settings.WX_SECRET
  api = f"https://api.weixin.qq.com/sns/oauth2/access_token?appid={appid}&secret={secret}&code=[code]&grant_type=authorization_code"
  r = requests.get(api)
  return r.json()

通过 access_token 换取 用户信息

def request_userinfo(access_token: str, openid: str):
  api = f"https://api.weixin.qq.com/sns/userinfo?access_token={access_token}&openid={openid}&lang=zh_CN"
  r = requests.get(api)
  return r.json()

用户信息入库

需要注意的是:微信返回的数据编码格式为 ISO-8859-1 ,需要转换成 utf-8

def convert_string_encoding(s: str, from_encoding: str, to_encoding: str) -> str:
  """先根据 from_encoding 转换成bytes,然后在 decode 为 to_encoding 的字符串
  """
  return bytes(s, encoding=from_encoding).decode(to_encoding)
nickname = convert_string_encoding(resp['nickname'], 'ISO-8859-1', 'utf-8')

跳转回原来访问的链接

我的实现方式是在数据库保存一条记录,以 statekey

from app.models import WXUser, RedirectUrl
from utils import get_wx_authorize_url, get_random_string
from django.shortcuts import redirect

def login_required(func):
  def wrapper(request, *args, **kwargs):
    openid = request.openid
    try:
      user = WXUser.objects.get(openid=openid)
      request.wxuser = user
    except WXUser.DoesNotExist:
      state = get_random_string()
      redirect_url = get_wx_authorize_url(state=state)

      # 存储跳转链接
      try:
        r = RedirectUrl.objects.get(state=state)
      except RedirectUrl.DoesNotExist:
        r = RedirectUrl()
        r.state = state
      origin_url = request.get_raw_uri()
      r.url = origin_url
      r.save()

      return redirect(redirect_url)
    return func(request, *args, **kwargs)

  return wrapper

然后在我们设置的回调接口(会带上 codestate )里面,就可以通过 state 从数据库里获取原链接。

class RedirectUrl(BaseModel):
  state = models.TextField(unique=True)
  url = models.TextField()

0x02 中间件

这个中间件使用 jwt 作为认证手段,为什么不使用 session ,那可以讲另一个故事了,这里不赘述了。

HTTP_AUTHORIZATION (请求头中的 Authorization 字段)或者 key 为 jwttokencookie 中抽取出 jwt token ,从中解析出 openid ,添加到 request 变量中,之后就可以在后续的 views里面通过 request.openid 直接获取 openid 了。

def jwt_decode(token: Union[str, bytes]) -> tuple:
  """
  :param token : 可以是 bytes 也可以是 str,如果是 str,会先 encode 转成 bytes
  :return: 第一个参数为 payload,第二个参数为异常类型
  """
  if isinstance(token, str):
    token = token.encode()
  secret = settings.JWT_SECRET
  try:
    return jwt.decode(token, secret, algorithms=["HS256"]), None
  except Exception as e:
    # 统一捕捉异常:
    # jwt.exceptions.DecodeError
    # jwt.exceptions.InvalidSignatureError
    # jwt.exceptions.ExpiredSignatureError
    return None, e


class JWTAuthMiddleware(object):
  """
  小程序认证中间件
  """

  def __init__(self, get_response=None):
    self.get_response = get_response

  def __call__(self, request, *args, **kws):
    token = self.get_authorization_header(request)

    payload, error = jwt_decode(token)
    if not error:
      openid = payload['openid']
      request.openid = openid
    else:
      request.openid = None

    response = self.get_response(request, *args, **kws)
    return response

  def get_authorization_header(self, request):
    """
    从 AUTHORIZATION 请求头或者cookie 中获取 jwt code
    cookie 的 jwt code 的 key 为 jwtcode
    :param request:
    :return: rawtoken
    """

    auth_header = request.META.get('HTTP_AUTHORIZATION', '')
    cookie = request.COOKIES

    rawtoken = None
    if auth_header != "":
      try:
        rawtoken = auth_header.split(" ")[1]
      except IndexError as e:
        pass
    if 'jwttoken' in cookie:
      rawtoken = cookie['jwttoken']
    return rawtoken

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
名片管理系统python版
Jan 11 Python
python实现Decorator模式实例代码
Feb 09 Python
Python SVM(支持向量机)实现方法完整示例
Jun 19 Python
python正则表达式去除两个特殊字符间的内容方法
Dec 24 Python
谈谈Python中的while循环语句
Mar 10 Python
浅析Python 实现一个自动化翻译和替换的工具
Apr 14 Python
Python实现某论坛自动签到功能
Aug 20 Python
jupyter notebook 添加kernel permission denied的操作
Apr 21 Python
Python使用pyenv实现多环境管理
Feb 05 Python
Python使用openpyxl复制整张sheet
Mar 24 Python
Python深度学习之实现卷积神经网络
Jun 05 Python
Django框架中视图的用法
Jun 10 Python
python tkinter库实现气泡屏保和锁屏
Jul 29 #Python
django迁移数据库错误问题解决
Jul 29 #Python
python实现桌面托盘气泡提示
Jul 29 #Python
python实现桌面气泡提示功能
Jul 29 #Python
pycharm设置鼠标悬停查看方法设置
Jul 29 #Python
django rest framework vue 实现用户登录详解
Jul 29 #Python
python实现倒计时小工具
Jul 29 #Python
You might like
php使用GD库创建图片缩略图的方法
2015/06/10 PHP
PHP导出带样式的Excel示例代码
2016/08/28 PHP
PHP会员找回密码功能的简单实现
2016/09/05 PHP
PHP获取文本框、密码域、按钮的值实例代码
2017/04/19 PHP
prototype 的说明 js类
2006/09/07 Javascript
jQuery 数据缓存data(name, value)详解及实现
2010/01/04 Javascript
jquery实现类似淘宝星星评分功能有截图
2014/09/15 Javascript
Javascript的setTimeout()使用闭包特性时需要注意的问题
2014/09/23 Javascript
JQuery查找DOM节点的方法
2015/06/11 Javascript
AngularJS 文件上传控件 ng-file-upload详解
2017/01/13 Javascript
JavaScript表单验证完美代码
2017/03/02 Javascript
简单实现js菜单栏切换效果
2017/03/04 Javascript
Vue响应式添加、修改数组和对象的值
2017/03/20 Javascript
Bootstrap4如何定制自己的颜色和风格
2018/02/26 Javascript
JS使用tween.js动画库实现轮播图并且有切换功能
2018/07/17 Javascript
ES6 Promise对象概念及用法实例详解
2019/10/15 Javascript
Vue中keep-alive组件作用详解
2020/02/04 Javascript
vue实现购物车加减
2020/05/30 Javascript
JavaScript TAB栏切换效果的示例
2020/11/05 Javascript
在Python中使用cookielib和urllib2配合PyQuery抓取网页信息
2015/04/25 Python
python爬虫入门教程--正则表达式完全指南(五)
2017/05/25 Python
Python解决线性代数问题之矩阵的初等变换方法
2018/12/12 Python
详解Python odoo中嵌入html简单的分页功能
2019/05/29 Python
Django框架视图介绍与使用详解
2019/07/18 Python
python 多进程队列数据处理详解
2019/12/23 Python
Python使用扩展库pywin32实现批量文档打印实例
2020/04/09 Python
浅谈Keras中shuffle和validation_split的顺序
2020/06/19 Python
智能钱包:Ekster
2019/11/21 全球购物
Nike墨西哥官网:Nike MX
2020/08/30 全球购物
大三自我鉴定范文
2013/10/05 职场文书
竞职演讲稿范文
2014/01/11 职场文书
暑期学习心得体会
2014/09/02 职场文书
四风问题对照检查材料
2014/09/22 职场文书
2015新员工试用期工作总结
2014/12/12 职场文书
2015年学校信息技术工作总结
2015/05/25 职场文书
幽默导游词应该怎么写?
2019/08/26 职场文书