django 网站接入微信登录,在手机非微信浏览器端登录,想用微信开放平台的 h5 唤起微信客户端登录,代码如下,怎么还是总提示:请在微信客户端打开链接呢? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
python30
V2EX    Python

django 网站接入微信登录,在手机非微信浏览器端登录,想用微信开放平台的 h5 唤起微信客户端登录,代码如下,怎么还是总提示:请在微信客户端打开链接呢?

  •  
  •   python30 229 天前 1839 次点击
    这是一个创建于 229 天前的主题,其中的信息可能已经有所发展或是发生改变。

    django 网站接入微信登录,在手机非微信浏览器端登录,想用微信开放平台的 h5 唤起微信客户端登录,代码如下,怎么还是总提示:请在微信客户端打开链接呢?

    views.py

    def generate_state(): """ 生成一个随机的 state 参数 """ return secrets.token_urlsafe(16) # 生成一个 16 字节的随机字符串 def wechat_login(request): """ 微信登录入口,根据设备类型选择不同的授权方式 """ user_agent = request.META.get('HTTP_USER_AGENT', '').lower() # 判断是否为微信浏览器 is_wechat_browser = 'micromessenger' in user_agent # 判断是否为手机端 is_mobile = any(keyword in user_agent for keyword in ['mobile', 'android', 'iphone', 'ipod']) # 生成随机的 state 参数 state = generate_state() request.session['wechat_state'] = state # 将 state 存储在会话中 if is_wechat_browser: # 微信浏览器内登录(使用微信公众号的 OAuth2.0 授权) wechat_auth_url = ( f"https://open.weixin.qq.com/connect/oauth2/authorize" f"?appid={settings.WECHAT_MP_APP_ID}" # 使用微信公众号的 AppID f"&redirect_uri={settings.WECHAT_MP_REDIRECT_URI}" # 微信公众号的回调地址 f"&response_type=code" f"&scope=snsapi_userinfo" # 使用 snsapi_userinfo 或 snsapi_base f"&state={state}#wechat_redirect" ) elif is_mobile: # 手机端浏览器登录(使用微信开放平台的 H5 登录) wechat_auth_url = ( f"https://open.weixin.qq.com/connect/oauth2/authorize" f"?appid={settings.WECHAT_OPEN_APP_ID}" # 使用微信开放平台的 AppID f"&redirect_uri={settings.WECHAT_OPEN_REDIRECT_URI}" # 微信开放平台的回调地址 f"&response_type=code" f"&scope=snsapi_userinfo" # 使用 snsapi_login f"&state={state}#wechat_redirect" ) else: # 电脑端浏览器登录(使用微信开放平台的扫码登录) wechat_auth_url = ( f"https://open.weixin.qq.com/connect/qrconnect" f"?appid={settings.WECHAT_OPEN_APP_ID}" # 使用微信开放平台的 AppID f"&redirect_uri={settings.WECHAT_OPEN_REDIRECT_URI}" # 微信开放平台的回调地址 f"&response_type=code" f"&scope=snsapi_login" # 使用 snsapi_login f"&state={state}#wechat_redirect" ) return redirect(wechat_auth_url) def get_wechat_h5_login_url(request): """ 生成微信开放平台的 H5 登录 URL """ # 生成随机的 state 参数 state = generate_state() request.session['wechat_state'] = state # 微信开放平台的 H5 登录 URL wechat_h5_login_url = ( f"https://open.weixin.qq.com/connect/oauth2/authorize" f"?appid={settings.WECHAT_OPEN_APP_ID}" # 微信开放平台的 AppID f"&redirect_uri={settings.WECHAT_OPEN_REDIRECT_URI}" # 回调地址 f"&response_type=code" f"&scope=snsapi_login" # 使用 snsapi_login f"&state={state}" # 可选参数,用于防止 CSRF 攻击 f"#wechat_redirect" ) return JsonResponse({ 'success': True, 'login_url': wechat_h5_login_url, }) def filter_username(nickname): """ 过滤掉不允许的字符,只保留字母、数字、_、- """ # 只保留字母、数字、_、- filtered = re.sub(r'[^\w-]', '', nickname) return filtered def generate_unique_username(nickname): """ 根据微信昵称生成唯一的用户名 """ # 过滤特殊字符 base_username = filter_username(nickname) # 如果过滤后的用户名为空,使用默认用户名 if not base_username: base_username = 'wechat_user' # 添加随机后缀 random_suffix = ''.join(random.choices(string.ascii_lowercase + string.digits, k=4)) username = f"{base_username}_{random_suffix}" # 检查用户名是否已存在 while User.objects.filter(username=username).exists(): random_suffix = ''.join(random.choices(string.ascii_lowercase + string.digits, k=4)) username = f"{base_username}_{random_suffix}" return username def wechat_callback(request): """ 微信登录回调处理 """ code = request.GET.get('code') state = request.GET.get('state') if not code: return HttpResponse('授权失败,未获取到 code') # 验证 state 参数 if state != request.session.get('wechat_state'): return HttpResponse('非法请求,state 参数不匹配') # 清除会话中的 state request.session.pop('wechat_state', None) # 判断是否为微信浏览器 user_agent = request.META.get('HTTP_USER_AGENT', '').lower() is_wechat_browser = 'micromessenger' in user_agent # 根据设备类型选择 appid 和 secret if is_wechat_browser: # 微信浏览器内登录(使用微信公众号的 appid 和 secret ) appid = settings.WECHAT_MP_APP_ID secret = settings.ECHAT_MP_APP_SECRET else: # 非微信浏览器登录(使用微信开放平台的 appid 和 secret ) appid = settings.WECHAT_OPEN_APP_ID secret = settings.WECHAT_OPEN_APP_SECRET # 通过 code 获取 access_token token_url = ( f"https://api.weixin.qq.com/sns/oauth2/access_token" f"?appid={appid}" f"&secret={secret}" f"&code={code}" f"&grant_type=authorization_code" ) respOnse= requests.get(token_url) data = response.json() access_token = data.get('access_token') openid = data.get('openid') uniOnid= data.get('unionid') # 获取 unionid if not access_token or not openid: return HttpResponse('获取 access_token 失败') # 获取用户信息 user_info_url = ( f"https://api.weixin.qq.com/sns/userinfo" f"?access_token={access_token}" f"&openid={openid}" ) respOnse= requests.get(user_info_url) response.encoding = 'utf-8' user_info = response.json() # 根据 unionid 查找或创建用户 user, created = User.objects.get_or_create(uniOnid=unionid) if created: # 生成唯一的用户名 nickname = user_info.get('nickname', '微信用户') user.username = generate_unique_username(nickname) user.set_unusable_password() # 微信登录用户不需要密码 user.nickname = user_info.get('nickname', '') # 更新昵称 user.avatar = user_info.get('headimgurl', '') # 更新头像 user.wechat_nickname = user_info.get('nickname', '') # 更新微信昵称 user.save() # 登录用户 login(request, user) return redirect('/') # 登录成功后跳转到首页 def get_js_sdk_config(request): """ 获取 JS-SDK 配置 """ try: access_token = get_access_token(settings.WECHAT_MP_APP_ID, settings.WECHAT_MP_APP_SECRET) except Exception as e: return JsonResponse({'error': str(e)}, status=500) # 获取 JSAPI Ticket ticket_url = f"https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token={access_token}&type=jsapi" respOnse= requests.get(ticket_url) jsapi_ticket = response.json().get('ticket') # 生成签名参数 nonce_str = generate_nonce_str() timestamp = int(time.time()) url = request.build_absolute_uri() # 生成签名 signature = generate_signature(jsapi_ticket, nonce_str, timestamp, url) # 返回 JS-SDK 配置 return JsonResponse({ 'appId': settings.WECHAT_MP_APP_ID, # 公众号的 AppID 'timestamp': timestamp, 'nonceStr': nonce_str, 'signature': signature, 'wechatOpenAppId': settings.WECHAT_OPEN_APP_ID, # 微信开放平台的 AppID 'wechatOpenRedirectUri': settings.WECHAT_OPEN_REDIRECT_URI, # 微信开放平台回调地址 'wechatMpRedirectUri': settings.WECHAT_MP_REDIRECT_URI # 微信开放平台回调地址 }) def get_access_token(appid, appsecret): """ 获取微信 access_token ,并缓存 """ # 先从缓存中获取 access_token access_token = cache.get('wechat_access_token') if access_token: return access_token # 缓存中没有,则从微信接口获取 url = f"https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={appid}&secret={appsecret}" respOnse= requests.get(url) data = response.json() if 'access_token' in data: access_token = data['access_token'] # 将 access_token 缓存 7000 秒(微信的有效期是 7200 秒) cache.set('wechat_access_token', access_token, 7000) return access_token else: raise Exception(f"获取 access_token 失败: {data}") 

    urls.py

     path('wechat/login/', wechat_login, name='wechat_login'), path('wechat/callback/', wechat_callback, name='wechat_callback'), path('get_js_sdk_config/', get_js_sdk_config, name='get_js_sdk_config'), # 获取 JS-SDK 配置 path('wechat/get_wechat_h5_login_url/', get_wechat_h5_login_url, name='get_wechat_h5_login_url'),#手机端非微信浏览器登录 

    login.html 方式 1

    <script src="https://res.wx.qq.com/open/js/jweixin-1.6.0.js"></script> <div class="container reg"> <!-- 微信登录按钮 --> <button id="wechat-login">微信登录</button> </div> <script> document.getElementById('wechat-login').addEventListener('click', function () { // 判断是否为微信浏览器 var userAgent = navigator.userAgent.toLowerCase(); var isWechatBrowser = userAgent.indexOf('micromessenger') !== -1; var isMobile = /mobile|android|iphone/i.test(userAgent); if (isWechatBrowser || !isMobile) { // 微信浏览器内或电脑端,直接跳转到后端生成的微信登录 URL window.location.href = "/user/wechat/login/"; // 这里假设 Django 反向解析后的实际 URL } else { // 手机端非微信浏览器,使用微信开放平台的 H5 登录 // 向后端请求微信开放平台的 H5 登录 URL var xhr = new XMLHttpRequest(); xhr.open('GET', '/user/wechat/get_wechat_h5_login_url/', true); // 后端生成 H5 登录 URL 的接口 xhr.Onreadystatechange= function () { if (xhr.readyState === 4 && xhr.status === 200) { var respOnse= JSON.parse(xhr.responseText); if (response.success) { // 跳转到微信开放平台的 H5 登录页面 window.location.href = response.login_url; } else { alert('获取微信登录链接失败,请稍后重试。'); } } }; xhr.send(); } }); </script> 

    login.html 方式 2

    <script src="https://res.wx.qq.com/open/js/jweixin-1.6.0.js"></script> <div class="container reg"> <!-- 微信登录按钮 --> <button id="wechat-login">微信登录</button> </div> <script> document.getElementById('wechat-login').addEventListener('click', function () { // 判断是否为微信浏览器 var userAgent = navigator.userAgent.toLowerCase(); var isWechatBrowser = userAgent.indexOf('micromessenger')!== -1; var isMobile = /mobile|android|iphone/i.test(userAgent); if (isWechatBrowser ||!isMobile) { // 微信浏览器内或电脑端,直接跳转到后端生成的微信登录 URL window.location.href = "/user/wechat/login/"; // 这里假设 Django 反向解析后的实际 URL } else { // 获取 JS-SDK 配置 var xhr = new XMLHttpRequest(); xhr.open('GET', '/user/get_js_sdk_config/', true); xhr.Onreadystatechange= function () { if (xhr.readyState === 4 && xhr.status === 200) { var cOnfig= JSON.parse(xhr.responseText); wx.config({ debug: true, // 调试模式 appId: config.appId, // 公众号的 AppID timestamp: config.timestamp, // 时间戳 nonceStr: config.nonceStr, // 随机字符串 signature: config.signature, // 签名 jsApiList: ['launchApplication'] // 需要使用的 JS 接口 }); wx.ready(function () { // 尝试唤醒微信客户端 wx.launchApplication({ appId: config.appId, // 这里需要替换为实际的微信 AppID extraData: '', success: function () { // 唤醒成功,跳转到微信登录 URL window.location.href = "/user/wechat_login/"; // 这里假设 Django 反向解析后的实际 URL }, fail: function (res) { alert('唤醒微信客户端失败,请检查您的微信是否安装或尝试其他登录方式。'); } }); }); wx.error(function (res) { alert('JS-SDK 配置出错,请刷新页面重试。'); }); } }; xhr.send(); } }); </script> 

    setting.py 里面也配置好了上面的 appid 相关参数与回调地址,并且在电脑 pc 端,微信浏览器内都可以成功登录了,就是在手机非浏览器端,不管怎么操作,都是提示:请在微信客户端内打开链接

    麻烦各位大佬看看是哪里的原因? 一直无法用 h5 的 js-sdk 在手机端唤起微信客户端登录?谢谢

    2 条回复    2025-02-23 17:47:44 +08:00
    xavierchow
        1
    xavierchow  
       229 天前   1
    python 不是很熟,粗粗看了一下,如果你想要在非微信浏览器用微信登录的话,应该是快速登录功能: https://developers.weixin.qq.com/doc/oplatform/Website_App/WeChat_Login/Wechat_Login.html

    你现在判断到手机端非微信浏览器的时候,调用 get_wechat_h5_login_url 去拿重定向的地址,但是里面的 API 用错了,https://open.weixin.qq.com/connect/oauth2/authorize 这个是公众号网页授权登录(需要在微信浏览器内);你要唤起微信做快速登录是这个 https://open.weixin.qq.com/connect/qrconnect API ,具体流程你可以参考贴的官方快速登录功能的文档。
    python30
        2
    python30  
    OP
       228 天前
    @xavierchow 谢谢,我换了这个接口后,跟在电脑 pc 端一样了,生成了一个二维码,让扫码登录,我看别的手机端网站,点微信登录,可以跟在微信浏览器内一样,确认一下就直接微信登录了,以前有 wx.launchApplication 唤醒微信登录,后来取消这个了,现在也不知道用啥办法了。
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     3434 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 32ms UTC 05:05 PVG 13:05 LAX 22:05 JFK 01:05
    Do have faith in what you're doing.
    ubao snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86