跪拜 Guibai
← Back to the summary

WeChat QR Login in Java: WxJava SDK vs Raw OAuth 2.0 Calls

In Java, implementing WeChat QR code login is based on the WeChat Open Platform's website application and the OAuth 2.0 protocol. You first need to create a "website app" on the Open Platform, pass review, get an AppID and AppSecret, and configure the authorized callback domain (must be an ICP-registered domain; local development requires intranet penetration).

The entire flow can be summarized as: backend generates authorization link → frontend displays QR code → user scans and authorizes → WeChat calls your interface with a code → backend uses the code to exchange for access_token and openid → fetch user info and complete local login.

There are two mainstream implementation methods; you can choose according to your project situation.


Method 1: Use WxJava SDK (recommended)

WxJava is the most widely used Java SDK in WeChat development. It encapsulates token management, API calls, and other details, significantly reducing boilerplate code.

  1. Add dependency
<dependency>
    <groupId>com.github.binarywang</groupId>
    <artifactId>weixin-java-mp</artifactId>
    <version>4.6.0</version> <!-- It's recommended to use a newer version -->
</dependency>
  1. Configure WxMpService
@Configuration
public class WxConfig {
    @Value("${wechat.appid}") private String appId;
    @Value("${wechat.secret}") private String secret;

    @Bean
    public WxMpService wxMpService() {
        WxMpService service = new WxMpServiceImpl();
        WxMpInMemoryConfigStorage config = new WxMpInMemoryConfigStorage();
        config.setAppId(appId);
        config.setSecret(secret);
        service.setWxMpConfigStorage(config);
        return service;
    }
}
  1. Generate the QR link and handle the callback

WxJava provides a method to directly build the authorization URL, making callback handling simpler:

@RestController
@RequestMapping("/wechat")
public class WechatLoginController {
    @Autowired private WxMpService wxMpService;

    // Generate authorization link (frontend renders as QR code)
    @GetMapping("/qrconnect")
    public String qrConnect(@RequestParam String redirectUri,
                            @RequestParam String state) throws Exception {
        // Ensure redirectUri matches the callback domain configured on the Open Platform
        return wxMpService.getOAuth2Service()
            .buildAuthorizationUrl(redirectUri, "snsapi_login", state);
    }

    // WeChat callback endpoint
    @GetMapping("/callback")
    public String callback(@RequestParam("code") String code,
                           @RequestParam("state") String state) throws Exception {
        // 1. Validate state (prevent CSRF, details later)
        // 2. Exchange code for access_token and openid
        WxOAuth2AccessToken accessToken = wxMpService.getOAuth2Service()
            .getAccessToken(code);
        String openId = accessToken.getOpenId();

        // 3. Get user info (optional)
        WxOAuth2UserInfo userInfo = wxMpService.getOAuth2Service()
            .getUserInfo(accessToken, null);

        // 4. Execute local login/registration logic, return login state (e.g., JWT)
        return "login_success";
    }
}

Method 2: Manually call HTTP APIs

If you don't want an extra dependency, you can directly call WeChat's APIs with RestTemplate or WebClient. This lets you see each layer in detail.

  1. Build the authorization URL (consistent with official docs)
String url = "https://open.weixin.qq.com/connect/qrconnect" +
    "?appid=" + appId +
    "&redirect_uri=" + URLEncoder.encode(redirectUri, "UTF-8") +
    "&response_type=code" +
    "&scope=snsapi_login" +
    "&state=" + state +
    "#wechat_redirect";
  1. In the callback, exchange code for access_token

WeChat's endpoint is fixed at https://api.weixin.qq.com/sns/oauth2/access_token, requiring appid, secret, code, and grant_type=authorization_code.

String tokenUrl = "https://api.weixin.qq.com/sns/oauth2/access_token" +
    "?appid=" + appId +
    "&secret=" + appSecret +
    "&code=" + code +
    "&grant_type=authorization_code";

ResponseEntity<String> resp = restTemplate.getForEntity(tokenUrl, String.class);
JSONObject json = JSON.parseObject(resp.getBody());
String accessToken = json.getString("access_token");
String openId = json.getString("openid");
  1. Get user info (optional)

After getting access_token and openid, call https://api.weixin.qq.com/sns/userinfo to get nickname, avatar, etc.:

String userInfoUrl = "https://api.weixin.qq.com/sns/userinfo" +
    "?access_token=" + accessToken +
    "&openid=" + openId;
// Parse the returned JSON to get fields like nickname, headimgurl

Two key security and design points

① The state parameter must be validated

state is used to prevent CSRF attacks. Before generating the authorization link, the server should generate a random value (e.g., UUID) and store it in the current session (Session or Redis). When the callback arrives, the server must verify that the state returned by WeChat matches the stored value; otherwise, reject the login.

② openid is the unique identifier within a website app

The same user has different openids under different website apps; but within the same website app, openid is stable and unique. The local user table should use this field as the association key for WeChat login, not relying on nickname or avatar (which users can change). If you need a unified user identifier across apps, use unionid (requires multiple apps bound to the same Open Platform account).


Choosing between the two methods

· For development efficiency and an existing Spring ecosystem: choose WxJava. It handles token caching, HTTP errors, JSON parsing, and other details, with less code and lower maintenance cost. · For zero external dependencies and full control over HTTP calls: choose manual calls. Suitable for dependency-sensitive projects, or scenarios needing deep customization of requests and responses.

Regardless of the method, the callback domain must be preconfigured and strictly match the actual callback address; this is the most common sticking point when integrating. During development, use intranet penetration tools (like ngrok) to generate a temporary public domain for debugging, and switch to the official ICP-registered domain before going live.