微博登录和session恢复过程

  • 登录
    • 预登录
    • 获取验证码
    • 登录
      • 密码密文sp计算
      • 登录请求
    • 跨域广播登录
      • 解决cookie设置不上的问题
    • 跨域广播之后
  • 恢复session

完整源码参考我的pixiv-to-weibo项目,只实现了核心部分,没做容错处理

登录

预登录

这一步是为了获取加密公钥和nonce,因为以前新浪没用HTTPS,必须手动加密。其中用户名编码su算法为BASE64(URI编码(用户名))

    async def _pre_login(self, su):async with self._session.get('https://login.sina.com.cn/sso/prelogin.php', params={'entry':    'weibo','callback': 'sinaSSOController.preloginCallBack','su':       su,'rsakt':    'mod','checkpin': '1','client':   'ssologin.js(v1.4.18)'}) as r:return self.__get_jsonp_response(await r.text())

返回方式是JSONP,有用的是这几个字段:用来加密的公钥pubkey,防止回放攻击的nonceservertime,之后请求要用的rsakv,是否需要验证码showpin,验证码请求要用的pcid

获取验证码

如果预登录返回的数据中showpin为1则需要验证码。获取验证码的请求如下,返回的是验证码图片数据

    async def _input_verif_code(self, pcid):async with self._session.get('https://login.sina.com.cn/cgi/pin.php', params={'r': random.randint(0, 100000000),'s': '0','p': pcid}) as r:img_data = await r.read()self._show_image(img_data)return input('输入验证码:')

登录

密码密文sp计算

sp算法为:转十六进制文本(RSA(servertime + '\t' + nonce + '\n' + 密码)),其中RSA公钥在预登录时返回

    @staticmethoddef _get_secret_password(password, servertime, nonce, pubkey):key = rsa.PublicKey(int(pubkey, 16), 65537)res = rsa.encrypt(f'{servertime}\t{nonce}\n{password}'.encode(), key)res = binascii.b2a_hex(res)return res.decode()

登录请求


登录请求如下,这个请求完成后就可以发微博了。很多微博登录的源码都只做到这一步,但是24小时后session会失效,少了后面的步骤则不能恢复session

    async def login(self, username, password):su = base64.b64encode(quote_plus(username).encode()).decode()data = await self._pre_login(su)async with self._session.post('https://login.sina.com.cn/sso/login.php', params={'client': 'ssologin.js(v1.4.19)',}, data={'entry':       'weibo','gateway':     '1','from':        '','savestate':   '7','qrcode_flag': 'false','useticket':   '1','pagerefer':   'https://login.sina.com.cn/crossdomain2.php?action=logout&''r=https%3A%2F%2Fpassport.weibo.com%2Fwbsso%2Flogout%3Fr%3''Dhttps%253A%252F%252Fweibo.com%26returntype%3D1','vsnf':        '1','su':          su,'service':     'miniblog','servertime':  data['servertime'],'nonce':       data['nonce'],'pwencode':    'rsa2','rsakv':       data['rsakv'],'sp':          self._get_secret_password(password, data['servertime'],data['nonce'], data['pubkey']),'sr':          '1366*768','encoding':    'UTF-8','prelt':       '233','url':         'https://weibo.com/ajaxlogin.php?framelogin=1&callback=''parent.sinaSSOController.feedBackUrlCallBack','returntype':  'META','door':        '' if data['showpin'] == 0else await self._input_verif_code(data['pcid'])}) as r:return await self.__handle_login_page(str(r.url), await r.text())

返回内容为一个网页,其中有脚本跳转到下一个地址

     <html><head><title>新浪通行证</title><meta http-equiv="refresh" content="0; url='https://login.sina.com.cn/crossdomain2.php?action=login&entry=weibo&......'"/><meta http-equiv="Content-Type" content="text/html; charset=GBK" /></head><body bgcolor="#ffffff" text="#000000" link="#0000cc" vlink="#551a8b" alink="#ff0000"><script type="text/javascript" language="javascript">location.replace("https://login.sina.com.cn/crossdomain2.php?action=login&entry=weibo&......");</script></body></html>

微博登录中跳转的网址是不确定的,有时候是https://login.sina.com.cn/crossdomain2.php,有时候是https://passport.weibo.com/visitor/visitor,整个流程不能写死,所以我专门写了一个函数来处理这些跳转

    async def __handle_login_page(self, url, res):while True:# 登录页if url.startswith('https://login.sina.com.cn/sso/login.php'):next_url = self.__get_next_url(res)# ...# 登录完毕elif url.startswith('https://weibo.com'):return '/home' in url# 未知的地址else:print('未知的地址:' + url)print(res)return Falseasync with self._session.get(next_url, headers={'Referer': url  # 访问visitor?a=restore必须带referer}) as r:url = str(r.url)res = await r.text()

跨域广播登录

这是上一步跳转到的crossdomain2.php干的事,就是你打开微博偶尔会看到的"Signing in …"的页面。旧版sso登录脚本没有混淆并且有中文注释,有兴趣的自己看吧。arrURL是要发送请求的URL列表,请求完成后调用location.replace跳转

广播URL中要关注的是passport.weibo.com这个域名,会设置一些恢复session用的cookie,Python中有些坑会导致这些cookie设置不上,这个后面再说

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=GBK" />
<title>Sina Passport</title><script charset="utf-8" src="https://i.sso.sina.com.cn/js/ssologin.js"></script>
</head>
<body>
Signing in ...
<script>
try{sinaSSOController.setCrossDomainUrlList({"retcode":0,"arrURL":["......"]});}catch(e){var msg = e.message;var img = new Image();var type = 1;img.src = 'https://login.sina.com.cn/sso/debuglog?msg=' + msg +'&type=' + type;}try{sinaSSOController.crossDomainAction('login',function(){location.replace('https://passport.weibo.com/wbsso/login?......');});}catch(e){var msg = e.message;var img = new Image();var type = 2;img.src = 'https://login.sina.com.cn/sso/debuglog?msg=' + msg +'&type=' + type;}
</script>
</body>
</html>

__handle_login_page中对这个页面的处理如下

            # 跨域登录广播elif url.startswith('https://login.sina.com.cn/crossdomain2.php'):async def cross_domain_callback(url_, i):async with self._session.get(url_, params={'callback': 'sinaSSOController.doCrossDomainCallBack','scriptId': 'ssoscript' + str(i),'client': 'ssologin.js(v1.4.2)'}) as r_:await r_.read()url_list = re.search(r'setCrossDomainUrlList\((.*?)\);', res)[1]url_list = json.loads(url_list)['arrURL']await asyncio.gather(*(cross_domain_callback(url, i) for i, url in enumerate(url_list)))next_url = self.__get_next_url(res)

解决cookie设置不上的问题

这个是因为新浪返回的cookie中expire的星期几用的是全称,而Python标准库中的正则假设它用的是3个字符的简称:\w{3},\s[\w\d\s-]{9,11}\s[\d:]{8}\sGMT

>>> import http.cookies
>>> cookie = http.cookies.SimpleCookie()
>>> cookie.load('SRF=155......; expires=Sunday, 15-Apr-2029 13:18:56 GMT; path=/; domain=.passport.weibo.com')
>>> cookie
<SimpleCookie: >
>>> cookie.load('SRF=155......; expires=Sun, 15-Apr-2029 13:18:56 GMT; path=/; domain=.passport.weibo.com')
>>> cookie
<SimpleCookie: SRF='155......'>

我的解决方法是在脚本开头用黑科技把这个正则改了,不过不保证可移植性,如果不能用就自己想办法吧

import http.cookies
http.cookies.BaseCookie._BaseCookie__parse_string.__defaults__ = (re.compile(r"""\s*                            # Optional whitespace at start of cookie(?P<key>                       # Start of group 'key'[""" + http.cookies._LegalKeyChars + r"""]+?   # Any word of at least one letter)                              # End of group 'key'(                              # Optional group: there may not be a value.\s*=\s*                          # Equal Sign(?P<val>                         # Start of group 'val'"(?:[^\\"]|\\.)*"                  # Any doublequoted string|                                  # or\w{3,},\s[\w\d\s-]{9,11}\s[\d:]{8}\sGMT  # Special case for "expires" attr|                                  # or[""" + http.cookies._LegalValueChars + r"""]*      # Any word or empty string)                                # End of group 'val')?                             # End of optional value group\s*                            # Any number of spaces.(\s+|;|$)                      # Ending either at space, semicolon, or EOS.""", re.ASCII | re.VERBOSE),   # re.ASCII may be removed if safe.
)

跨域广播之后

广播完成后脚本跳转到https://passport.weibo.com/wbsso/login,然后通常会重定向到https://weibo.com/ajaxlogin.phpredirect是下一个跳转地址

<html><head><script language='javascript'>parent.sinaSSOController.feedBackUrlCallBack({"result":true,"userinfo":{"uniqueid":"......","userid":null,"displayname":null,"userdomain":"?wvr=5&lf=reg"},"redirect":"https:\/\/weibo.com\/nguide\/interest"});</script></head><body></body></html>

__handle_login_page中对这个页面的处理如下

            # 调用parent.sinaSSOController.feedBackUrlCallBack跳转到weibo.com/nguide/interestelif url.startswith('https://weibo.com/ajaxlogin.php'):res_ = self.__get_jsonp_response(res)next_url = res_['redirect']

然后经过一堆重定向到你的微博主页https://weibo.com/....../home

恢复session

24小时后session会失效,此时再访问微博首页会被重定向到https://login.sina.com.cn/sso/login.php,之后按登录流程处理即可

    async def restore_session(self):async with self._session.get('https://weibo.com/') as r:return await self.__handle_login_page(str(r.url), await r.text())

有时候会重定向到新浪访客系统https://passport.weibo.com/visitor/visitor?a=enter,这个页面的脚本也是没有混淆,带中文注释的。不过不管哪种方式最后都会到https://login.sina.com.cn/sso/login.php

            # 新浪访客系统,用来恢复cookieelif url.startswith('https://passport.weibo.com/visitor/visitor'):if 'a=enter' in url:next_url = 'https://passport.weibo.com/visitor/visitor?a=restore&cb=restore_back&from=weibo'else:res_ = self.__get_jsonp_response(res)next_url = (f'https://login.sina.com.cn/sso/login.php?entry=sso&alt={res_["data"]["alt"]}'f'&returntype=META&gateway=1&savestate={res_["data"]["savestate"]}'f'&url=https%3A%2F%2Fweibo.com%2F%3Fdisplay%3D0%26retcode%3D6102')

微博登录和session恢复过程相关推荐

  1. 【49.Auth2.0认证与授权过程-微博开放平台认证授权过程-百度开放平台认证授权过程-社交登录实现(微博授权)-分布式Session问题与解决方案-SpringSession整合-Redis】

    一.知识回顾 [0.三高商城系统的专题专栏都帮你整理好了,请点击这里!] [1-系统架构演进过程] [2-微服务系统架构需求] [3-高性能.高并发.高可用的三高商城系统项目介绍] [4-Linux云 ...

  2. python爬虫登录微博_为爬虫获取登录cookies: 使用Charles和requests模拟微博登录

    上一节,我们讲了如何配置Charles代理,这一节我们通过模拟微博登录这个例子来看看如何使用Charles分析网站加载流程,顺便把微博模拟登录的Python代码也给实现了. 1. 用Charles记录 ...

  3. js调试微博登录案例

    js调试 五.微博登录案例 1.分析流程 手动操作流程 访问首页https://weibo.com 输入用户名和密码 点击登录 如果有验证码,就输入验证码验证 成功跳转到微博首页面 请求流程分析过程 ...

  4. java加按钮_如何从零开始对接第三方登录(Java版):QQ登录和微博登录

    阅读本文约需要8分钟 大家好,我是你们的导师,我每天都会在这里给大家分享一些干货内容(当然了,周末也要允许老师休息一下哈).上次老师跟大家分享了HashMap和TreeMap的知识,今天跟大家分享下对 ...

  5. oracle ora 00283,【案例】Oracle报错ORA-16433非归档丢失redo无法启动的恢复过程

    天萃荷净 Oracle研究中心案例分析:运维DBA反映Oracle数据库处理非归档模式,redo文件损坏常规修复无法正常open数据库. 本站文章除注明转载外,均为本站原创: 转载自love wife ...

  6. 数据库startup报错_SQL Server数据库恢复过程内部–数据库STARTUP命令

    数据库startup报错 A database recovery process is an essential requirement for database systems, It can be ...

  7. web app 第三方登录-微博登录(一)

    在最近参与的一个android项目中,使用的是web app 的形式,就是android提供容器,但是里面的内容都由H5实现.由于不是原生的app,给集成第三方登录带来一些困难.下面把集成的过程分享下 ...

  8. 【航天信息开票软件V3.0金税盘版安装恢复过程】有坑有心得

    @[TOC]航天信息开票软件V3.0金税盘版安装恢复过程 2023年5月11日 昨天下午我司财务打开"开票软件V3.0"提示更新,但是更新过程中出现错误.再启动 开票软件V3.0 ...

  9. 思科交换机的登录、密码恢复与应用

    一.登录交换机 首先找一根CONSOLE线将计算机的串口与交换机的CONSOLE口相连.(注:CONSOLE[控制台]线的一端为RJ45的水晶头,一端用DB9的串口,如果想要自己制作这根线,可以使用一 ...

最新文章

  1. java验证码源码_Java通用验证码程序及应用示例(提供源码下载)
  2. Meta小冰英伟达一起搞事!亚洲首个元宇宙生态联合体来了
  3. TC工具后台模式_聊天能赚钱?来聊后台批量添加账号,伪装女性聊天赚钱内幕...
  4. JDBC事务--软件开发三层架构--ThreadLocal
  5. 观察者模式与职责链模式的相同和不同_GOF设计模式(策略模式,职责链模式)...
  6. linux-practice(23-24)
  7. 计算机组装与维修技能大赛视频,2013年计算机组装与维修技能大赛试题及答案真题...
  8. vmware workstation不可恢复错误:(vthread-7)
  9. Linux环境中的帮助命令有,Linux下的帮助命令
  10. java8调用unsafe_JDK8---UnSafe类实现CAS乐观锁
  11. Java、JSP报刊订阅管理系统的设计与实现
  12. 气候制度的转变和森林的丧失放大了亚马逊森林的火灾
  13. Pssp-mvirt: 基于多视图深度学习架构的肽二级结构预测
  14. 遗传算法之基因型与表现型的相互转换
  15. 在线教育未来的发展前景如何?
  16. KONG (API网关) 用CORS处理跨域,针对:非简单请求
  17. canvas实现一个线性图
  18. MM 供应商账户组后台配置步骤
  19. 在unity中读取并可视化dicom图像(fo-dicom / C# / unity)
  20. 浏览器渲染原理以及性能优化

热门文章

  1. SpringBoot 项目上传文件异常【java.io.IOException: Stream closed】
  2. (深度学习论文精读总结)You Only Look Once: Unified, Real-Time Object Detection
  3. ubuntu使用python读串口_21.python通过pyserial读写串口--2013-06-02
  4. C#ObjectArx Cad创建点线块
  5. 美国计算机硕士学校,美国计算机硕士不同学校申请难度大盘点(下篇)
  6. 转——解决游戏王DL的steam版锁区问题
  7. Oracle数据库实验4 Oracle数据库安全管理
  8. Java峰值和削峰_架构设计之流量削峰
  9. Android之集成极光推送
  10. 你给文字描述,AI艺术作画,精美无比!附源码,快来试试!