1. 程式人生 > >django-微信小程式登入

django-微信小程式登入

小程式登入邏輯
前端通過呼叫wx.login()獲取code, 將code和使用者基本資訊傳送到後端,後端通過request.get向微信伺服器傳送get請求獲取使用者openid和session_key,手動新增jwt-token,利用jwt自動校驗使用者是否登入

 


小程式前端觸發login事件

<button class="confirm-btn"  open-type="getUserInfo" bindgetuserinfo="login" wx:if="{{regFlag==false}}">授權登入</button>

js程式碼:login事件接收的引數 e.detail.userInfo儲存了使用者基本資訊,呼叫wxlogin方法獲取使用者的code,傳送到後端

login:function( e ){
        var that = this;
        if( !e.detail.userInfo ){
            app.alert( { 'content':'登入失敗,請再次點選~~' } );
            return;
        }

        var data = e.detail.userInfo;
        wx.login({
            success:function( res ){
                if( !res.code ){
                    app.alert( { 
'content':'登入失敗,請再次點選~~' } ); return; } data['code'] = res.code; wx.request({ url:app.buildUrl( '/member/login' ), header:app.getRequestHeader(), method:'POST', data:data, success:
function( res ){ if( res.data.code != 200 ){ app.alert( { 'content':res.data.msg } ); return; } app.setCache( "token",res.data.data.token ); that.goToIndex(); } }); } }); }

後端程式碼:

使用者模型類繼承自django自帶的使用者模型,新增三個使用者資訊欄位

class User(AbstractUser):
    USER_GENDER_CHOICES = (
        (0, ''),
        (1, ''),
    )
sex = models.SmallIntegerField(choices=USER_GENDER_CHOICES, default=1, verbose_name="性別") avatar = models.CharField(max_length=50, default="", null=True, blank=True, verbose_name="頭像") openid = models.CharField(max_length=64, db_index=True, verbose_name='openid') class Meta: db_table = 'tb_users' verbose_name = '使用者' verbose_name_plural = verbose_name

類檢視:傳送請求獲取使用者的openid,用openid來查詢是否使用者已經存在,不存在建立信的使用者,統一手動簽發jwt_token返回

class WechatLoginView(APIView):
    """
    微信登入邏輯
    """

    def post(self, request):
        # 前端傳送code到後端,後端傳送網路請求到微信伺服器換取openid
        code = request.data.get('code')
        if not code:
            return Response({'message': '缺少code'}, status=status.HTTP_400_BAD_REQUEST)

        url = "https://api.weixin.qq.com/sns/jscode2session?appid={0}&secret={1}&js_code={2}&grant_type=authorization_code" \
            .format(settings.APP_ID, settings.APP_KEY, code)
        r = requests.get(url)
        res = json.loads(r.text)
        openid = res['openid'] if 'openid' in res else None
        # session_key = res['session_key'] if 'session_key' in res else None
        if not openid:
            return Response({'message': '微信呼叫失敗'}, status=status.HTTP_503)

        # 判斷使用者是否第一次登入
        try:
            user = User.objects.get(openid=openid)
        except Exception:
            # 微信使用者第一次登陸,新建使用者
            username = request.data.get('nickname')
            sex = request.data.get('sex')
            avatar = request.data.get('avatar')
            user = User.objects.create(username=username, sex=sex, avatar=avatar)
            user.set_password(openid)

        # 手動簽發jwt
        jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
        jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER

        payload = jwt_payload_handler(user)
        token = jwt_encode_handler(payload)

        resp_data = {
            "user_id": user.id
            "username": user.username,
            "avatar": user.avatar,
            "token": token,
        }

        return Response(resp_data)
    

補充:jwt的配置

REST_FRAMEWORK = {
  'DEFAULT_AUTHENTICATION_CLASSES': (
  'rest_framework_jwt.authentication.JSONWebTokenAuthentication',
  'rest_framework.authentication.SessionAuthentication',
  'rest_framework.authentication.BasicAuthentication',
  ),
}

JWT_AUTH = {
  # 指明token的有效期
  'JWT_EXPIRATION_DELTA': datetime.timedelta(days=7),
}