>

微信平台开荒0二,微信授权注册与登入

- 编辑:www.bifa688.com -

微信平台开荒0二,微信授权注册与登入

用户模块---QQ登6
流程图图片 1
QQ登入文书档案:

        上一个月公司网址登入注册改版,做了基于微信的第二方授权登入和挂号,下边说的是网址选用微信授权完毕登陆注册,。踩了部分坑,今后写下去, 刚好梳理一下事先的笔触, 假如能帮到有供给的人,那更加好了。

1.背景

在微信中定义了菜单,然后就供给取得用户的报到音讯来不一致用户的操作,比如是什么人下单,当前用户的账号里有些许money等等。那其间基本因素就是绑定用户,也正是赢得用户的身份音讯。

流程简述:
一.当点击qq登陆Logo时,进入生成登入url的接口
二.在前者的回调函数中跳转到qq登陆的扫码页面
叁.扫码登6后,qq会引导code访问申请时钦定的回调地址,
使用code获取access_token
使用access_token最后得到openid
4用来判别用户是还是不是是第叁遍利用QQ登录
伍.是,再次来到绑定/注册,页面第三回使用QQ登入,额外决断,是不是曾经注册账号
伍.1是,统1跳转到绑定/注册分界面,
伍.一.一将openid和账号实行绑定/注册,手动调用jwt功效重返jwt,id,username

       微信授权登录的优点是, 通过联网微信登6效用,用户可应用微信帐号火速登入你的网址,下落注册门槛。 那是微信官方文档微信OAuth二.0授权登6的流程图,后来又做了钉钉登入,QQ登6,开采都以同等的流水生产线和公理, 都是基于OAuth二.0贯彻的,这一个会了,钉钉登入,qq登6也就能够了,1通百通。

2.分析

授权进程相比复杂,可是辛亏是逐一的流水生产线。

graph LR
用户关注服务号-->在服务号中发送url给用户
在服务号中发送url给用户-->用户点击URL并同意
用户点击URL并同意-->得到code
得到code-->向服务器获取AccessToken
向服务器获取AccessToken-->获取用户信息

对于程序的调用流程来讲是:

  • 其三方发起微信授权登六请求,微信用户同意授权第叁方应用后,微信会拉起应用或重定向到第3方网站,并且带上授权权且票据code参数;

  • 由此code参数加上AppID和AppSecret等,通过API换取access_token;

  • 通过access_token实行接口调用,获取用户核心数据财富或赞助用户完成基本操作。

这远要比QQ的授权要复杂一些,至少在伸手进程中需求多appid和appsecret参数才具符合规律通讯。

图片 2

工作规律

5.2否,再次来到首页,手动调用jwt效率重返jwt,id,username

图片 3

率先步 配置权力和回调uri:
  • 确认在服务号后台的[开辟者宗旨中]查看[接口权限列表],[网页服务]栏目中的[网页授权获取用户主题新闻]是否是[已获得]的图景,那个供给服务号经过证实过才行;
  • 输入用于拍卖回调的页面域名,注意域名不能够带http://

切实贯彻:

        进入正题, 准备职业轻松说下, 在微信开放平台注册账号, 配置好AppID和AppSecret,设置好授权回调域名(注:主要,授权回调地址必须在此域名下)。

第一步 发给用户,用户同意授权,获取code:
https://open.weixin.qq.com/connect/oauth2/authorize?appid=${appid}&redirect_uri=${redirect_uri}&response_type=code&scope=${scope}&state=${state}#wechat_redirect

[图表上传战败...(image-5796八壹-151451686917三)]

参数 说明
appid 公众号的标识,在微信后台里可以找到
redirect_uri 授权之后重定向需要调用的地址
scope 授权的作用域,snsapi_base直接授权了,只能获得用户的openid,snsapi_userinfo,这个可以继续通过用户的openid获取进一步的用户信息
state 重定向之后需要保留的参数,值由调用者指定,任意值
#wechat_redirect 直接点击链接可以不放这个参数,如果是读文章,已经读了一半用这个参数可以保留阅读进度

这一步的第2作用正是用来获得进一步广播发表应用的一时code,须要用那个code加上AppID和AppSecret来换调用api所急需的access_token。
得逞调用之后,须要用户授权,同意微信平台将回调此前大家加以的redirect_uri地址,以get的点子传回code和从前给定的state参数。

采用到的模块:

第一步:获取code

请确认你的网址使用已经获得了网页授权效用域(scope=snsapi_login), 你能够在前者放置也许在后端重定向到 以下链接:https://open.weixin.qq.com/connect/qrconnect?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect ,

参数表达:

图片 4

注意, redirect_uri需求张开urlEncode编码, 必须在授权域名下。否则会油不过生redirect_url错误的升迁,授权退步。用户同意后会重定向到redirect_uri的路由上,并带上code和state参数。redirect_uri?code=CODE&state=STATE, 到这一步获取到了code。

例如,问卷网微信登录

也得以在协调的网址页面嵌入微信登入贰维码,用户使用微信扫码授权后透过JS将code重回给网址,这样不要求跳转到微信域名下 登6再回去,流畅性越来越好些。

例如:问卷网网页内嵌微信登入2维码

温馨网页嵌入微信登入二维码必要在页面引进微信的JS文件(日了吉娃娃,复制不回复了,只好截图了):

图片 5

在须要选用微信登入的地点实例以下JS对象

var obj = new WxLogin({

id:"login_container",

appid: "",

scope: "",

redirect_uri: "",

state: "",

style: "",

href: ""

});

图片 6

其三步 通过code换取网页授权access_token:

跟上贰个步骤是很类似的,组合3个url,通过get方式呼吁

https://api.weixin.qq.com/sns/oauth2/access_token?appid=${APPID}&secret=${SECRET}&code=${CODE}&grant_type=authorization_code
参数 说明
appid 公众号的标识
secret 公众号的secret密钥
code 第二步中请求获得的临时票据code
grant_type authorization_code,默认参数

例行情形下以json格式重临:

{
   "access_token":"ACCESS_TOKEN",
   "expires_in":7200,
   "refresh_token":"REFRESH_TOKEN",
   "openid":"OPENID",
   "scope":"SCOPE"
}
参数 说明
access_token 网页授权接口调用凭证,此access_token与基础支持的access_token不同
expires_in access_token接口调用凭证超时时间,单位(秒)
refresh_token 用户刷新access_token需要调用另外一个接口,因为refresh_token会有更长的有效期,所以可以凭借refresh_token来再次获取access_token,简化获取code后再去获取access_token的步骤
openid 用户唯一标识,请注意,在未关注公众号时,用户访问公众号的网页,也会产生一个用户和公众号唯一的OpenID
scope 用户授权的作用域,使用逗号(,)分隔

假诺调用错误那么会有1个荒唐的新闻再次回到,具体能够参见【全局再次回到码】

import urllib

urllib.parse.urlencode(query)  # 将字典转换为url路径中的查询字符串

urllib.parse.parse_qs(qs)  # 将查询字符串格式数据转换为python的字典

urllib.request.urlopen(url, data=None)

在python后端发起http请求,

如果data为None,发送GET请求,

如果data不为None,发送POST请求

response.read().decode()
返回response响应对象,可以通过read()读取响应体数据,需要注意读取出的响应体数据为bytes类型

第二步, 通过code获取access_token

经过上一步获取到的code参数,获取access_token

伸手方法: GET

参数表达:

图片 7

准确重临:

{

"access_token":"ACCESS_TOKEN",

"expires_in":7200,

"refresh_token":"REFRESH_TOKEN",

"openid":"OPENID",

"scope":"SCOPE",

"unionid": "o6_bmasdasdsad6_2sgVt7hMZOPfL"}

参数表明:

图片 8

这一步获取到, access_token,  openid, unionid, 这里对四个参数举行, access_token 是调用授权接口的调用凭证,这几个access_token无需举行缓存。还有3个access_token 是全局唯一接口调用凭据是供给缓存下来,限制时间为两小时,有调用频次限制的。openid是以此用户对应当前利用的不二法门标志,比方说,你唯有二个网址使用,那二个openid正是用户对应你的网址选拔的天下无双标记。 后来,你又新开垦了个app,和公众号,那么您的各种应用对应同2个用户是有两样openid的, 这年你一定须求同二个用户对应你的不等选用具备唯一性标示,那样技巧把各类应用打通,那年就须要利用unionid了。你必要把你的公众号和动用绑定在同一开放平台下。同一用户,对同三个微信开放平台下的不如应用,unionid是1律的。这正是unionid的最主要成效。

第六步 拉取用户音信:

构建以下url,通过get方式得到

https://api.weixin.qq.com/sns/userinfo?access_token=${ACCESS_TOKEN}&openid=${OPENID}&lang=zh_CN
参数 描述
access_token 网页授权接口调用凭证,注意:此access_token与基础支持的access_token不同
openid 用户的唯一标识
lang 返回国家地区语言版本,zh_CN 简体,zh_TW 繁体,en 英语

重返值还是是json格式

{
   "openid":"${OPENID}",
   "nickname":"${NICKNAME}",
   "sex":"${1}",
   "province":"${PROVINCE}"
   "city":"${CITY}",
   "country":"${COUNTRY}",
    "headimgurl":    "http://wx.qlogo.cn/mmopen/g3MonUZtNHkdmzicIlibx6iaFqAc56vxLSUfpb6n5WKSYVY0ChQKkiaJSgQ1dZuTOgvLLrhJbERQQ4eMsv84eavHiaiceqxibJxCfHe/46", 
    "privilege":[
    "PRIVILEGE1"
    "PRIVILEGE2"
    ],
    "unionid": "o6_bmasdasdsad6_2sgVt7hMZOPfL"
}
参数 描述
openid 用户的唯一标识
nickname 用户昵称
sex 用户的性别,值为1时是男性,值为2时是女性,值为0时是未知
province 用户个人资料填写的省份
city 普通用户个人资料填写的城市
country 国家,如中国为CN
headimgurl 用户头像,最后一个数值代表正方形头像大小(有0、46、64、96、132数值可选,0代表640*640正方形头像),用户没有头像时该项为空。若用户更换头像,原有头像URL将失效。
privilege 用户特权信息,json 数组,如微信沃卡用户为(chinaunicom)
unionid 只有在用户将公众号绑定到微信开放平台帐号后,才会出现该字段。详见获取用户基本信息(UnionID机制)更新

这里大约举行一下openid和unionid的分化:

  • 每种用户对每一个公众号的OpenID是唯一的。对于差别公众号,同一用户的openid区别,公众号可因此本接口来依据OpenID获取用户宗旨音信,包涵小名、头像、性别、所在城市、语言和关注时间。
  • 多少个公众号,或在公众号、移动应用之间联合用户帐号的急需,要求前往微信开放平台(open.weixin.qq.com)绑定公众号后,才可利用UnionID机制来满意上述须求。在回去的用户大旨音讯中,能够用unionid来分别用户的唯1性。

手动调用jwt生成token用于注解登陆情状

第三步:使用access_token 获取用户音信

呼吁方法:    GET

参数表达:

图片 9

毋庸置疑再次回到结果:

{

"openid":"OPENID",

"nickname":"NICKNAME",

"sex":1,

"province":"PROVINCE",

"city":"CITY",

"country":"COUNTRY",

"headimgurl": "",

"privilege":[

"PRIVILEGE1",

"PRIVILEGE2"

],

"unionid": " o6_bmasdasdsad6_2sgVt7hMZOPfL"

}

图片 10

从那之后,已经取获得用户音讯。可以创立用户会话。实现用户的注册和登入。


使用openid获取unionid

做网址使用微信授权中间境遇点小插曲, 因为集团工作在此以前是用微信公众号落成的授权,保存的是openid, 做了网址使用之后就不可能采纳openid作为用户数据表的微信字段了,须求选拔unionid才具保险集团多少个使用对于同样用户的唯1性。所以, 需求把前面包车型客车几80000用户的openid退换为unionid在用户数量表里保存。后来,查了下文书档案,微信提供了openid转unionid的接口。

先是步, 先获取全局唯一接口调用凭据access_token。

接口调用表达:

https请求形式: GET,

 

参数表达:

图片 11

注意, 这个access_token 跟上边微信授权提到的access_token未有半毛钱关系, 这个access_token 供给缓存下来,因为这一个接口有调用频次限制, 好像每一天最多可以调用伍仟次,能够保存在redis只怕memcache里,设置过期时间为7200秒,最棒小于7200 ,举个例子你能够安装九千后过期,过期后再度调用这些接口获取。

第二步,获取Unionid

接口调用表达

http请求方式: GET

参数表明:

图片 12

例行状态下,微信会重临下述JSON数据包给公众号

{

"subscribe": 1,

"openid": "o6_bmjrPTlm6_2sgVt7hMZOPfL2M",

"nickname": "Band",

"sex": 1,

"language": "zh_CN",

"city": "广州",

"province": "广东",

"country": "中国",

"headimgurl":"",

"subscribe_time": 1382694957,

"unionid": " o6_bmasdasdsad6_2sgVt7hMZOPfL"

"remark": "",

"groupid": 0,

"tagid_list":[128,2]

}

参数表明:

图片 13

如此那般就用用户在此以前封存的openid 获取到Unionid了。

写了个四线程调用微信的接口,半个多小时就把几七千0用户的openid、更改为了Unionid了。

有不规则的地点,大概疑问招待留言。

三.注意事项

因为access_token能源相比单薄,一般选用存放大家微信服务程序的服务器来获得,简单来讲,要求2个特意的次序去拉取access_token,之后有所要求运用请求的顺序,都从服务器获取全局的access_token来促成调用。伊始的思量是每隔八千秒去调用三次拿走access_token的呼吁,然后存放在大局缓存中供全体选择。

from rest_framework_jwt.settings import api_settings

jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER
payload = jwt_payload_handler(user)
jwt_token = jwt_encode_handler(payload)

四.代码完成

上述内容是参谋网站学习整理所得:http://mp.weixin.qq.com/wiki/4/9ac2e7b1f1d22e9e57260f6553822520.html

itsdangerous模块用于生成token和剖析token

from itsdangerous import TimedJSONWebSignatureSerializer


serializer = TimedJSONWebSignatureSerializer(settings.SECRET_KEY, 300)
# 需要转换成token的数据
data = {'openid': openid}

# .dumps生成token,bytes类型,需要解码
token = serializer.dumps(data).decode()

# .loads将token解析为需要的数据,
openid = serializer.loads(token).get('openid')

模型类,保存QQ的openid和本站用户之间的涉嫌:

from django.db import models

class BaseModel(models.Model):
    """基类模型"""
    create_time = models.DateTimeField(auto_now_add=True, verbose_name="创建时间")
    update_time = models.DateTimeField(auto_now=True, verbose_name="更新时间")

    class Meta:
        # 指定BaseModel为抽象类,不会创建实体表
        abstract = True

class OAuthQQUser(BaseModel):
    """QQ登录的模型"""
    openid = models.CharField(max_length=64, verbose_name='openid', db_index=True)
    user = models.ForeignKey('user.User', on_delete=models.CASCADE, verbose_name='用户')
    objects = models.Manager()

    class Meta:
        db_table = 'tb_oauth_qq'
        verbose_name = 'QQ登录用户数据'
        verbose_name_plural = verbose_name

概念一个工具类,首要肩负生成token和表明token是或不是正确

class OAuthQQ(object):
    """用于qq登录的工具类"""

    def __init__(self, client_id=None, client_secret=None, redirect_uri=None, state=None):
        """QQ登录开发文档中需要的参数"""
        self.client_id = client_id or settings.QQ_CLIENT_ID
        self.client_secret = client_secret or settings.QQ_CLIENT_SECRET
        self.redirect_uri = redirect_uri or settings.QQ_REDIRECT_URI
        self.state = state or settings.QQ_STATE  # 用于保存登录成功后的跳转页面路径

在OAuthQQ工具类中新扩充生成登入url的措施

def generate_qq_login_url(self):
        """生成用于qq登录扫码的url地址"""
        params = {
            'response_type': 'code',  # 默认值
            'client_id': self.client_id,
            'redirect_uri': self.redirect_uri,
            'state': self.state,
            'scope': 'get_user_info',  # 用户勾选的授权范围,get_user_info表示,获取登录用户的昵称、头像、性别
        }
        url = 'https://graph.qq.com/oauth2.0/authorize?'
        # 拼接查询字符串,
        url  = parse.urlencode(params)
        return url

概念重临扫码QQ登陆url的接口

# 在点击qq登录图标时向接口发起请求
# 后端生成用于QQ扫码登录的页面的url地址
# 在前端回调函数中执行

# GET /oauth/qq/authorization/?state=xxx

class QQAuthUrlView(APIView):
    """获取QQ扫码登录的网址接口"""

    def get(self, request):
        """
        :return 扫码的url地址
        """
        state = request.query_params.get('state')
        oauthqq = OAuthQQ(state=state)
        qq_login_url = oauthqq.generate_qq_login_url()
        return Response({'qq_login_url': qq_login_url})

前端将code当参数字传送入后端接口,生成获取access_token的url
在OAuthQQ工具类新扩大,使用code请求并得到QQ的access_token,的方法

def get_qq_access_token(self, code):
        """获取access_token"""
        params = {
            'grant_type': 'authorization_code',
            'client_id': self.client_id,
            'client_secret': self.client_secret,
            'code': code,
            'redirect_uri': self.redirect_uri,
        }
        url = 'https://graph.qq.com/oauth2.0/token?'
        url  = parse.urlencode(params)
        # 向qq方发起http请求,获取包含access_token的查询字符串
        # 形式access_token=FE04************************CCE2&expires_in=7776000&refresh_token=88E4************************BE14
        try:
            response = request.urlopen(url)
            response_data = response.read().decode()
            # 讲查询字符串转换为python中的字典,[{}]
            data = parse.parse_qs(response_data)
            access_token = data.get('access_token', None)[0]
        except Exception as e:
            logger.error(e)
            raise Exception('获取access_token异常')
        return access_token

根据access_token生成得到openid的url
后端发送http请求,从重临值中收获openid

def get_qq_openid(self, access_token):
        """获取openid"""
        url = 'https://graph.qq.com/oauth2.0/me?access_token='
        url  = access_token
        logger.error(url)
        try:
            response = request.urlopen(url)
            response_data = response.read().decode()
            # 返回一个字符串  callback( {"client_id":"YOUR_APPID","openid":"YOUR_OPENID"} )n;
            data_dict = json.loads(response_data[10:-4])
            openid = data_dict.get('openid', None)
        except Exception as e:
            logger.error(e)
            raise Exception('获取openid异常')
        return openid

据他们说openid去看清,该用户是还是不是是第1回选择QQ登6作用.
定义类视图和serializers种类化器

class QQAuthUserView(GenericAPIView):
    """QQ登录后接口"""
    serializer_class = OAuthQQUserSerializer

    def get(self, request):
        """QQ登录"""
        code = request.query_params.get('code')
        if not code:
            return Response({'message': 'code不存在'}, 400)

        # 目标是通过 code获取access_token
        oauthqq = OAuthQQ()
        access_token = oauthqq.get_qq_access_token(code)

        # 通过access_token获取openid
        openid = oauthqq.get_qq_openid(access_token)

        # 获取openid后需要判断
        # oauthqquser = OAuthQQUser.get

        try:
            oauthqquser = OAuthQQUser.objects.get(openid=openid)
        except Exception as e:
            logger.error('此人未绑定或未注册:%s' % e)
            # 1.第一次用qq登录
            # 使用openid生成记录qq身份的token,以便注册或绑定时验证身份
            access_token = OAuthQQ.generate_save_user_token(openid)
            return Response({'access_token': access_token})
        # 1.1 已经注册本站账号--->跳转绑定界面
        # 1.2 未注册本站账号--->注册并绑定

        # 2.以前已经qq登录过(一定有本站账号)
        else:
            user = oauthqquser.user
            # 生成jwt_token,用于记录登录状态
            jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
            jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER
            payload = jwt_payload_handler(user)
            jwt_token = jwt_encode_handler(payload)

            data = {
                'user_id': user.id,
                'username': user.username,
                'token': jwt_token
            }
            return Response(data=data)

    def post(self, request):
        """QQ账号绑定和新增功能"""

        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        user = serializer.save()

        jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
        jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER
        payload = jwt_payload_handler(user)
        jwt_token = jwt_encode_handler(payload)

        data = {
            'user_id': user.id,
            'username': user.mobile,
            'token': jwt_token
        }
        return Response(data=data)

连串化器

class OAuthQQUserSerializer(serializers.Serializer):
    """创建或绑定QQ对应的本站用户"""
    access_token = serializers.CharField(label='操作凭证')
    mobile = serializers.RegexField(label='手机号', regex=r'^1[3-9]d{9}$')
    password = serializers.CharField(label='密码', max_length=20, min_length=8)
    sms_code = serializers.CharField(label='短信验证码')

    def validate(self, data):
        # 检验access_token
        access_token = data['access_token']
        openid = OAuthQQ.check_token_by_openid(access_token)
        if not openid:
            raise serializers.ValidationError('access_token失效')
        # 检验短信验证码
        mobile = data['mobile']
        sms_code = data['sms_code']
        redis_conn = get_redis_connection('verify_codes')
        real_sms_code = redis_conn.get('sms_%s' % mobile).decode()
        if not real_sms_code:
            raise serializers.ValidationError('短信验证码失效或过期')

        if real_sms_code != sms_code:
            raise serializers.ValidationError('短信验证码错误')

        # 如果用户存在,检查用户密码
        try:
            user = User.objects.get(mobile=mobile)
        except Exception as e:
            logger.error('本站用户不存在,等待注册---%s' % e)
            pass
        else:
            # 如果存在就校验密码
            password = data['password']
            if not user.check_password(password):
                raise serializers.ValidationError('密码错误')
            data['user'] = user

        data['openid'] = openid
        return data

    def create(self, validated_data):
        user = validated_data.get('user', None)
        if not user:
            # 用户不存在,先注册本站新用户
            user = User.objects.create_user(
                username=validated_data['mobile'],
                password=validated_data['password'],
                mobile=validated_data['mobile'],
            )
        # 新老用户都绑定QQ的openid
        OAuthQQUser.objects.create(
            openid=validated_data['openid'],
            user=user
        )
        return user

本文由必发88手机版发布,转载请注明来源:微信平台开荒0二,微信授权注册与登入