Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

WeChat Public Account Integration: OAuth2 Authorization and Template Messaging

Tech May 7 13

Registering in the WeChat Public Platform Sandbox

To begin development, register in the WeChat public platform sandbox environment:

https://mp.weixin.qq.com/debug/cgi-bin/sandboxinfo?action=showinfo&t=sandbox/index

Development Process Overview

1. Obtaining App ID and App Secret

    appID: wx89085e915d351cae
    appsecret: 64f87abfc664f1d4f11d0ac98b24c42d

Configure your server domain (e.g., 47.98.134.86) in the WeChat platform settings for web authorization.

2. Following the Official Account

After successful registration, you'll receive a QR code for a verified service account. Users need to scan this QR code to follow the account.

3. QR Code Generation and User Binding

Generate QR codes that users can scan. When scanned, user information is sent to WeChat, which then forwards the data to your specified redirect_uri (using MD5 hashing).

4. Callback Implementation

The callback endpoint (e.g., /callback/) should handle:

  • Authorization processing
  • User MD5 validation
  • WeChat ID retrieval
  • Database update with WeChat ID

5. Message Sending (Template Messages)

Template message functionality requires:

  • WeChat ID
  • Access token (valid for 2 hours)

Implementation Code

models.py

import hashlib
from django.db import models

class UserProfile(models.Model):
    username = models.CharField("Username", max_length=64, unique=True)
    password = models.CharField("Password", max_length=64)
    uid = models.CharField(verbose_name='User Unique ID', max_length=64, unique=True)
    wechat_id = models.CharField(verbose_name="WeChat ID", max_length=128, blank=True, null=True, db_index=True)

    def save(self, *args, **kwargs):
        # Generate unique ID when creating user
        if not self.pk:
            m = hashlib.md5()
            m.update(self.username.encode(encoding="utf-8"))
            self.uid = m.hexdigest()
        super(UserProfile, self).save(*args, **kwargs)

urls.py

from django.conf.urls import url
from django.contrib import admin
from wechat_integration import views

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^login/$', views.login),
    url(r'^bind/$', views.bind),
    url(r'^bind_qcode/$', views.bind_qcode),
    url(r'^callback/$', views.callback),
    url(r'^sendmsg/$', views.sendmsg),
]

Login View

def auth_required(func):
    @functools.wraps(func)
    def inner(request, *args, **kwargs):
        user_data = request.session.get('user_data')
        if not user_data:
            return redirect('/login/')
        return func(request, *args, **kwargs)
    return inner


def login(request):
    if request.method == "POST":
        username = request.POST.get('username')
        password = request.POST.get('password')
        user = models.UserProfile.objects.filter(username=username, password=password).first()
        
        if user:
            request.session['user_data'] = {'id': user.id, 'name': user.username, 'uid': user.uid}
            return redirect('/bind/')
    else:
        return render(request, 'login.html')

Official Account Binding View

@auth_required
def bind(request):
    return render(request, 'bind.html')

Binding Template (bind.html)

{% load staticfiles %}

<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>WeChat Account Binding</title>
</head>
<body>
<div style="width: 600px;margin: 0 auto">
    <h1>Please follow our service account and bind your personal profile (for future notifications)</h1>
    <div>
        <h3>Step 1: Follow the WeChat service account</h3>
        <img style="height: 100px;width: 100px" src="{% static "img/service_account_qr.jpg" %}">
    </div>
    <input type="button" value="Next: Get Binding QR Code" onclick="getBindingQRCode()">
    <div>
        <h3>Step 2: Bind your personal account</h3>
        <div id="qrcode" style="width: 250px;height: 250px;background-color: white;margin: 100px auto;"></div>
    </div>
</div>
<script src="{% static "js/jquery.min.js" %}"></script>
<script src="{% static "js/jquery.qrcode.min.js" %}"></script>
<script>
    function getBindingQRCode() {
        $.ajax({
            url: '/bind_qcode/',
            type: 'GET',
            success: function (result) {
                $('#qrcode').empty().qrcode({text: result.data});
            }
        });
    }
</script>
</body>
</html>

QR Code Generation View

@auth_required
def bind_qcode(request):
    response_data = {'status': 'success'}
    try:
        auth_url = "https://open.weixin.qq.com/connect/oauth2/authorize?appid={appid}&redirect_uri={redirect_uri}&response_type=code&scope=snsapi_userinfo&state={state}#wechat_redirect"
        auth_url = auth_url.format(
            appid=settings.WECHAT_CONFIG["app_id"],
            redirect_uri=settings.WECHAT_CONFIG["redirect_uri"],
            state=request.session['user_data']['uid']
        )
        response_data['data'] = auth_url
    except Exception as e:
        response_data = {'status': 'error', 'message': str(e)}

    return JsonResponse(response_data)

Callback View for Processing User Authorization

def callback(request):
    authorization_code = request.GET.get("code")
    user_state = request.GET.get("state")

    # Retrieve user's OpenID using the authorization code
    api_response = requests.get(
        url="https://api.weixin.qq.com/sns/oauth2/access_token",
        params={
            "appid": settings.WECHAT_CONFIG["app_id"],
            "secret": settings.WECHAT_CONFIG["app_secret"],
            "code": authorization_code,
            "grant_type": "authorization_code",
        }
    ).()
    
    openid = api_response.get("openid")
    
    if openid:
        models.UserProfile.objects.filter(uid=user_state).update(wechat_id=openid)
        return HttpResponse("<h1>Authorization successful! Your account has been linked.</h1>")
    else:
        return HttpResponse("<h1>Please complete the authorization in WeChat</h1>")

Template Message Sending

def send_message(request):
    def retrieve_access_token():
        """Obtain WeChat global interface access token (valid for 2 hours)"""
        response = requests.get(
            url="https://api.weixin.qq.com/cgi-bin/token",
            params={
                "grant_type": "client_credential",
                "appid": settings.WECHAT_CONFIG['app_id'],
                "secret": settings.WECHAT_CONFIG['app_secret'],
            }
        ).()
        
        return response.get("access_token")

    access_token = retrieve_access_token()
    user = models.UserProfile.objects.get(id=1)
    openid = user.wechat_id

    def dispatch_template_message():
        """Send template message to user"""
        payload = {
            "touser": openid,
            "template_id": settings.WECHAT_CONFIG['template_id'],
            "data": {
                "first": {
                    "value": "Hello valued user",
                    "color": "#173177"
                },
                "keyword1": {
                    "value": "Important notification",
                    "color": "#173177"
                },
            }
        }
        
        response = requests.post(
            url="https://api.weixin.qq.com/cgi-bin/message/template/send",
            params={'access_token': access_token},
            =payload
        )
        
        return response.()

    result = dispatch_template_message()

    return HttpResponse('Message sent successfully' if result.get('errcode') == 0 else 'Message sending failed')

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

SBUS Signal Analysis and Communication Implementation Using STM32 with Fus Remote Controller

Overview In a recent project, I utilized the SBUS protocol with the Fus remote controller to control a vehicle's basic operations, including movement, lights, and mode switching. This article is aimed...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.