Backend Development 10 min read

Implementing WeChat QR Code Login with Spring Boot and Thymeleaf

This tutorial explains how to build a WeChat QR‑code login system using Spring‑Boot, Thymeleaf, HttpClient and JSON, covering preparation steps, project configuration, OAuth2 flow, code examples for generating QR pages, handling callbacks, and customizing the login experience.

Java Captain
Java Captain
Java Captain
Implementing WeChat QR Code Login with Spring Boot and Thymeleaf

WeChat QR‑code login is popular because of high traffic on the WeChat platform; this article walks through the complete implementation using Spring‑Boot and Thymeleaf.

Demo Effect

Preparation

Obtain a WeChat Open Platform account and create a website application to get appId and appSecret .

Start ngrok locally to expose a public URL for OAuth callback.

Configure the ngrok address as the authorized callback domain in the WeChat application settings.

Technologies Used

Spring‑Boot

Thymeleaf

HttpClient

JSON (org.json)

Learning Goals

Generate a full‑screen QR code page and a customizable QR code page.

Analyze the integration flow and implement the required functionality.

List the technologies involved.

Implementation

Create Spring‑Boot Project and Add Dependencies

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>httpclient</artifactId>
    <version>4.1</version>
</dependency>
<dependency>
    <groupId>org.json</groupId>
    <artifactId>json</artifactId>
    <version>20160810</version>
</dependency>

Configuration File (application.properties)

spring.thymeleaf.prefix: classpath:/templates/
spring.thymeleaf.suffix: .html
# WeChat app secret
appsecret=
# WeChat app id
appid=
scope=snsapi_login
# Authorized callback domain
domain=http://test.xcx.cxylt.cn/

server.port=8083

Authorization Flow Explanation

WeChat OAuth2.0 login lets users authenticate with their WeChat identity. The flow (authorization_code mode) is:

User clicks the QR‑code login link; after authorizing, WeChat redirects back with a temporary code parameter.

The server exchanges code for an access_token using the appId and appSecret.

Using the access_token (and openid ) the server retrieves the user's basic profile.

In short, the QR code leads to a callback URL that receives code , which is then exchanged for an accessToken to obtain the user's information.

First QR Code Page (Backend Controller)

@RequestMapping("/")
public String index(Model model) throws UnsupportedEncodingException {
    String oauthUrl = "https://open.weixin.qq.com/connect/qrconnect?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect";
    String redirect_uri = URLEncoder.encode(callBack, "utf-8");
    oauthUrl = oauthUrl.replace("APPID", appid)
                     .replace("REDIRECT_URI", redirect_uri)
                     .replace("SCOPE", scope);
    model.addAttribute("name", "liuzp");
    model.addAttribute("oauthUrl", oauthUrl);
    return "index";
}

Corresponding Thymeleaf view (index.html):

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h1>hello! <label th:text="${name}"></label></h1>
    <a th:href="${oauthUrl}">点击扫码登录</a>
</body>
</html>

Callback Handling

@RequestMapping("/callBack")
public String callBack(String code, String state, Model model) throws Exception {
    logger.info("进入授权回调,code:{},state:{}", code, state);
    // 1. Exchange code for access_token
    String url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code";
    url = url.replace("APPID", appid).replace("SECRET", appsecret).replace("CODE", code);
    String tokenInfoStr = HttpRequestUtils.httpGet(url, null, null);
    JSONObject tokenInfoObject = new JSONObject(tokenInfoStr);
    // 2. Use access_token and openid to get user info
    String userInfoUrl = "https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID";
    userInfoUrl = userInfoUrl.replace("ACCESS_TOKEN", tokenInfoObject.getString("access_token"))
                             .replace("OPENID", tokenInfoObject.getString("openid"));
    String userInfoStr = HttpRequestUtils.httpGet(userInfoUrl, null, null);
    model.addAttribute("tokenInfoObject", tokenInfoObject);
    model.addAttribute("userInfoObject", userInfoStr);
    return "result";
}

Result page (result.html) displays the token and user information using Thymeleaf expressions.

Custom QR Code Page

Backend route for custom page:

@RequestMapping("/1")
public String index1(Model model) throws UnsupportedEncodingException {
    String redirect_uri = URLEncoder.encode(callBack, "utf-8");
    model.addAttribute("name", "liuzp");
    model.addAttribute("appid", appid);
    model.addAttribute("scope", scope);
    model.addAttribute("redirect_uri", redirect_uri);
    return "index1";
}

Corresponding view (index1.html) embeds the WeChat JS SDK to render a QR code inside a div with id login_container :

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>内嵌(自定义二维码)</title>
    <script src="http://res.wx.qq.com/connect/zh_CN/htmledition/js/wxLogin.js"></script>
</head>
<body>
    <h1>hello! <label th:text="${name}"></label></h1>
    <div id="login_container"></div>
    <script th:inline="javascript">
        var obj = new WxLogin({
            self_redirect: true,
            id: "login_container",
            appid: [[${appid}]],
            scope: [[${scope}]],
            redirect_uri: [[${redirect_uri}]],
            state: "",
            style: "",
            href: ""
        });
    </script>
</body>
</html>

Source Code

All source files are available at https://github.com/pengziliu/spring-boot-2.0-leaning .

If you find this tutorial helpful, feel free to like and share.

JavaSpring BootThymeleafOAuth2WeChatQR Login
Java Captain
Written by

Java Captain

Focused on Java technologies: SSM, the Spring ecosystem, microservices, MySQL, MyCat, clustering, distributed systems, middleware, Linux, networking, multithreading; occasionally covers DevOps tools like Jenkins, Nexus, Docker, ELK; shares practical tech insights and is dedicated to full‑stack Java development.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.