django 网站接入微信登录,在手机非微信浏览器端登录,想用微信开放平台的 h5 唤起微信客户端登录,代码如下,怎么还是总提示:请在微信客户端打开链接呢?
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}")
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 在手机端唤起微信客户端登录?谢谢
![]() | 1 xavierchow 229 天前 ![]() 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 ,具体流程你可以参考贴的官方快速登录功能的文档。 |
2 python30 OP @xavierchow 谢谢,我换了这个接口后,跟在电脑 pc 端一样了,生成了一个二维码,让扫码登录,我看别的手机端网站,点微信登录,可以跟在微信浏览器内一样,确认一下就直接微信登录了,以前有 wx.launchApplication 唤醒微信登录,后来取消这个了,现在也不知道用啥办法了。 |