• 小程序如何实现无感登录
  • 发布于 2个月前
  • 349 热度
    0 评论
由来
最近开发一个预约系统,需要区分普通用户和工作人员。由于账号密码/短信验证过于繁琐,因而选择记录openid实现无感登录。(基本小程序都这样操作)

同时事先在数据库中录入客户手机号,即可在用户登录时根据有无手机号来区分普通用户和工作人员。这样在项目交付时,工作人员和普通用户一样可以直接登录无感登录小程序


一. 开发思路

微信的openid是一种唯一标识用户身份的字符串。用户登录小程序,通过手机号快速验证组件获取动态令牌code,后端向微信服务器发送get请求并带上code获取每个用户唯一的openid,然后记录到mysql中,并签发token。该openid就是登录小程序的唯一凭证。


二.简单实现
获取openid,如果通过openid查不用户,就自动新建用户,并返回token。
#####LoginView###########

code = request.data.get("code")
appid = appid # 微信小程序的appid
appsecret = "xxxxxxxx" # 微信小程序的密钥,登录微信公众平台即可获取
# 获取openid和session_token
querystring = {"appid":appid,"js_code":code,"secret":appsecret,"grant_type":"authorization_code"}
jscode2session = requests.get('https://api.weixin.qq.com/sns/jscode2session',params=querystring)
if not jscode2session.json().get("errcode"):
            data = jscode2session.json()
            ########拿到openid#########
            openid=data.get("openid")
            #######去数据库比对,如果通过openid查到用户并且未被禁用,就新建##########
            try:
                user = models.UserInfo.objects.get(openid)
                if user.is_deleted: # 检查用户是否被禁用
                    return ErrorResponse(msg='用户已被禁用,无法登录',data=data,code=302)
            except models.UserInfo.DoesNotExist: 
               models.UserInfo.objects.create()
三.更进一步:通过手机号来区别普通用户和工作人员
openid虽然做到的唯一性验证,但是当用户数量庞大时,该如何区分用户角色:
1:手动在后台根据已有用户分配权限
2:登录时根据某一标识区分角色
方法一显然不靠谱,因为用户至少会超过1000人,方法二需要额外标识,显然手机号最合适。


3.1 前端获取手机号的动态令牌
小程序提供了手机号快速验证组件,方便我们获取手机号。
把bindgetphonenumber 事件回调中的动态令牌code传到开发者后台
 <view class="title">欢迎来到广盈预约</view>
  <view class="card">
    <view class="button">快捷登录</view>
    <button
      style="opacity: 0"
      class="bottom-button"
      open-type="getPhoneNumber|agreePrivacyAuthorization"
      bindgetphonenumber="getrealtimephonenumber"
      bindagreeprivacyauthorization="handleAgreePrivacyAuthorization"
    >
      同意隐私协议并授权手机号注册
    </button>
  </view>
</view>

Page({
  getPhoneNumber (e) { console.log(e.detail.code)  // 动态令牌 }
})
注意:如果你想获取用户手机号就必须添加用户授权《隐私保护协议》bindagreeprivacyauthorization,否则小程序无法上线。

3.2 后端带着动态令牌去微信服务器获取手机号
简单来说就是用户登录时数据库中没有手机号对应的用户,后端就会自动建立一个账号,并分配权限为普通用户,然后直接登录。
这样的话,只需要第一次登录时获取手机号,以后登录就可以直接进入系统。
class RegisterView(APIView):  
    authentication_classes = []
    permission_classes = []
    def getmobile(self,appid,code):
       # 堆代码 duidaima.com
        """获取用户的手机号"""
        try:
            appsecret = "cxxxxxxxxx"
            querystring = {"appid":appid,"secret":appsecret,"grant_type":"client_credential"}
            response = requests.get('https://api.weixin.qq.com/cgi-bin/token',params=querystring)
            access_token = response.json().get("access_token")
            querystring = {"access_token":access_token}
            headers = {"content-type": "application/json"}
            payload = {"code":code}
            mobile =requests.post(f"https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token={access_token}",json=payload,headers=headers)
            return mobile.json().get('phone_info').get('phoneNumber')
        except Exception as e:
            return None


    def post(self, request):   
        unionid =request.data.get("unionid")
        nickname =request.data.get("nickname")
        openid = request.data.get("openid")
        code = request.data.get("code")
        appid = request.data.get("appid")

        mobile = self.getmobile(appid=appid,code=code)
        if not mobile:
            return ErrorResponse(msg="手机号获取失败")

        defaults = {
            "openid":openid,
            "unionid":unionid,
            "mobile":mobile,
            "nickname":nickname,
        }

        """这条语句将查找一个符合mobile=mobile条件的记录,如果找到就更新 defaults中的字段 ,否则就创建
        注意: 查询的条件必须是唯一的,否则会造成多条数据返回而报错,这个逻辑同 get() 函数。
        注意: 使用的字段,没有唯一的约束,并发的调用这个方法可能会导致多条相同的值插入。
        """
        models.UserInfo.objects.update_or_create(mobile=mobile,defaults=defaults) 
        models.User_GZH.objects.get_or_create(unionid=unionid, defaults={'unionid':unionid})
        return DetailResponse()

用户评论