美文网首页微信小程序程序员微信小程序
使用django开发微信小程序后端

使用django开发微信小程序后端

作者: weidwonder | 来源:发表于2017-01-15 21:18 被阅读11131次

    tips: 本文面向的对象是已经会使用django开发web后端的人员

    微信小程序后端与普通web的区别

    微信小程序的后端开发和普通的restful API 大致上相同,只不过要注意以下几点限制

    • 必须使用HTTPS协议请求后端服务器
    • 不支持COOKIE
    • 不支持django内置的user登录, 因为它使用的是微信的用户系统

    应对方法

    • 对于HTTPS的限制, 很简单, 去godaddy等网站申请一个https证书, 下载后使用nginx指定即可, 可以参照此文章, 这篇文章的证书是自己生成的, 这里需要替换为申请的证书

    • 不支持cookie, django原生的session机制就会失效

    • 不支持django内置的user登录, 因为它使用的是微信的用户系统

      对于上边这两个问题,我使用了JWT来保证了用户的在线验证. 那么什么是JWT呢, 可以看下推酷的这篇文章了解一下, 简要的来说就是用户登录以后, 原先保存在cookie里边的一个随机的sessionid变成了保存在http头部的Authorization字段的一个token值, 这个值是服务端自身加密的, 客户端无需解密, 只要服务端知道这个token对应这个用户就好, 当然这里也有很多的附加功能, 比如超时等等, 不再赘述

      然而网上有很多的jwt开源项目, 比如django-jwt, rest-framework-jwt, 你都可以使用, 但是却不适用于微信小程序, 为什么这么说? 是因为这两个项目都和django内置的user相耦合, 在上边提出的第三个问题的地方会引起问题, 在尝试了rest-framework-jwt发现问题后, 我毅然决定自己使用pyjwt实现一个用户登录/鉴权的组件.

      首先要知道微信小程序的登录流程是:

      1. 客户端请求用户授权
      2. 用户授权成功
      3. 客户端或得到用户基本信息(包括code,没有openid的用户明文信息, 有openid的加密后的信息, 解密向量iv)
      4. 客户端把返回的信息发送到服务器
      5. 服务器使用code去微信服务器换取session_key
      6. 服务器用这个session_key+iv去解密用户密文, 得到用户完整信息(基本+openid)
      7. 将用户在服务器登录, 维持用户session(这里的失效时间微信约定是30天)

    看起来好像步骤很多, 但是我们没有必要去重新造轮子, 早有人已经写好认证流程python-weixin我们可以省去4-6的步骤, 那么剩下的问题就是如何解决第7步也就是维持session的问题了.

    因为jwt始终使用http头部的token进行验证这里我的思路是:

    1. 微信用户登录后, 返回客户端token, 并在缓存创建用户的session信息
    2. 客户端请求时附加http头Authorization=JWT <token>
    3. 使用中间件检验http头的token, 审查通过则在request上追加一个jwt_user属性(这里不想覆盖django自带user), 同时去缓存寻找这个用户的session信息, 加载到request.jwt_session, 审查如果不通过则jwt_user设置为None, jwt_session为一个空的session对象
    4. 使用认证方法, 对于需要进行登录的接口检验用户是否为None

    到这一步就已经完成了整个的用户鉴权/session持久化流程, 如果你只是为了了解django开发小程序注意的点到这里已经可以结束了, 下边我要介绍的是我实现的一套中间件逻辑, 有兴趣可以拿去直接使用.

    这里中间件我已经实现了参见django-jwt-session-auth, 调用模块内部的jwt_login函数, 登录你的用户时会返回一个token, 这个token将要返回客户端, 同时它也会做user的session缓存动作.下一次客户端带着Authorization=JWT <token>调用的时候中间件会直接将对应的user和session加载到request.jwt_userrequest.jwt_session, 这里你需要设置的只有设置两个值: USER_TO_PAYLOADPAYLOAD_TO_USER两个方法:
    * USER_TO_PAYLOAD: 根据当前登录的用户生成一个字典payload方法
    * PAYLOAD_TO_USER: 根据你之前生成的payload找到对应的用户

    注: 2017.1.15我这个组件还没有完整的readme, 后续会加上

    最后, 关于认证器, 如果你使用rest-framework可以直接继承BaseAuthenticationauthenticate方法里校验jwt_user是否为None即可, 如果直接使用django原生的view, 可以写一个装饰器装饰在类view的dispatch方法上或直接装饰在函数的view上.

    示例

    # django-jwt-session-auth设置, 放在settings.py文件中
    JWT_AUTH = {
        'PAYLOAD_TO_USER': 'user.auth.payload_to_user',
        'USER_TO_PAYLOAD': 'user.auth.user_to_payload',
    }
    
    # rest-framework验证器
    class WechatUserAuthentication(BaseAuthentication):
        def authenticate(self, request):
            if not request.jwt_user:
                msg = u'请先授权'
                raise exceptions.AuthenticationFailed(msg)
            return (request.jwt_user, request.jwt_user.uuid)
    
    # 原生django验证装饰器
    def login_required(func):
        @wraps(func)
        def verify_login(request, *args, **kwargs):
            if request.jwt_user:
                return func(request, *args, **kwargs)
            else:
                # 返回HTTP_401
        return verify_login
    

    相关文章

      网友评论

      • adef5428fe46:微信小程序上传的图片到后端打印出来怎么是'str'类型啊,我应该做什么样的处理?
      • hugh_fly:略有不同意见:用django内置user更方便,openid做用户名,密码用长随机数;
        登录时用直接把code传到后端,后端拿着code换session_info,从里面找到openid查user,然后把user传给django-jwt,手动生成jwt返回小程序;不需要重写任何组件。
        bf03c8ed8619:@Wallyye
        http://getblimp.github.io/django-rest-framework-jwt/#creating-a-new-token-manually
        Wallyye:方便指教一下吗?
        Wallyye:请问如何手动生成jwt?
      • 738515ffcee2:1、 7 中需要维护的session指的是session_key吗?
        2、 加载到jwt_session作用是什么呢?
        3、 django1.11是不是不能直接用您的开源代码?
        738515ffcee2:@weidwonder 再请教一下,jwt_login中,get_jwt_session应该是有生成session和存到缓存里的操作才对,但是现在看没有这样的实现呀?有save()也没有调用到这个函数。
        738515ffcee2:@weidwonder 感谢回复!还要一个问题,就是你写的中间件中,新用户登陆的时候调用get_jwt_session,但是里面没有生成session?
        weidwonder:好久不做小程序了, 有些忘记, 见谅哈
        1. 指的是微信小程序官方提供的session
        2. jwt_session是参照session做的, 目的是防止和session冲突, 以保留admin相关功能
        3. 1.11出来之后没有测试, 如果有什么问题可以提出一个issue
      • 30ce11e561ee:Django 通过render(requests,"模板.html")返回一个视图,但是想返回一个wxml怎么办啊!本人小白,求指条路。😑
        30ce11e561ee: @若鸟 我本来就是wxml,但是render渲染不了wxml,难道小程序不是通过view渲染?
        weidwonder:@若鸟 其实我感觉你直接把html改为wx文件即可
        weidwonder:@若鸟 我没使用过渲染,不好意思啊
      • 这网站起个名字真难啊:期待更详细的教程
      • 知晓程序:你好!我们是爱范儿旗下专注于小程序生态的公众号知晓程序(微信号 zxcx0101)。我们很赞赏你的文章,希望能获得转载授权。授权后,你的文章将会在知晓程序社区(minapp.com)、爱范儿、AppSo 等渠道发布,我们会注明来源和作者姓名。
        知晓程序:@weidwonder 感谢:heart:
        weidwonder:@知晓程序 可以转载
      • kevin_X:阔以
        weidwonder:@kevin_X 谢谢打赏
        weidwonder:@kevin_X 还不打赏一下

      本文标题:使用django开发微信小程序后端

      本文链接:https://www.haomeiwen.com/subject/tqcubttx.html