Java实现微信扫码登录

0 阅读3分钟

在 Java 中实现微信扫码登录,核心是基于微信开放平台的网站应用与 OAuth 2.0 协议。你需要先在开放平台创建“网站应用”并通过审核,获得 AppID 和 AppSecret,并配置好授权回调域(必须是已备案的域名,本地开发需借助内网穿透)。

整个流程可以概括为:后端生成授权链接 → 前端展示二维码 → 用户扫码授权 → 微信回调你的接口并带上 code → 后端用 code 换取 access_token 与 openid → 获取用户信息并完成本地登录。

实现上有两种主流方式,你可以根据项目情况选择。


方式一:使用 WxJava SDK(推荐)

WxJava 是微信开发领域使用最广的 Java SDK,封装了 token 管理、API 调用等细节,能显著减少样板代码。

  1. 引入依赖
<dependency>
    <groupId>com.github.binarywang</groupId>
    <artifactId>weixin-java-mp</artifactId>
    <version>4.6.0</version> <!-- 建议使用较新版本 -->
</dependency>
  1. 配置 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. 生成二维码链接与处理回调

WxJava 提供了直接构建授权 URL 的方法,回调处理也更为简洁:

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

    // 生成授权链接(前端渲染为二维码)
    @GetMapping("/qrconnect")
    public String qrConnect(@RequestParam String redirectUri,
                            @RequestParam String state) throws Exception {
        // 确保 redirectUri 与开放平台配置的回调域一致
        return wxMpService.getOAuth2Service()
            .buildAuthorizationUrl(redirectUri, "snsapi_login", state);
    }

    // 微信回调接口
    @GetMapping("/callback")
    public String callback(@RequestParam("code") String code,
                           @RequestParam("state") String state) throws Exception {
        // 1. 校验 state(防 CSRF,后文详述)
        // 2. 用 code 换取 access_token 与 openid
        WxOAuth2AccessToken accessToken = wxMpService.getOAuth2Service()
            .getAccessToken(code);
        String openId = accessToken.getOpenId();

        // 3. 获取用户信息(可选)
        WxOAuth2UserInfo userInfo = wxMpService.getOAuth2Service()
            .getUserInfo(accessToken, null);

        // 4. 执行本地登录/注册逻辑,返回登录态(如 JWT)
        return "login_success";
    }
}

方式二:手动调用 HTTP API

如果不希望引入额外依赖,可以用 RestTemplate 或 WebClient 直接调用微信接口,这样能更清楚地看到每一层细节。

  1. 构建授权 URL(与官方文档一致)
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. 回调中用 code 换取 access_token

微信接口地址固定为 api.weixin.qq.com/sns/oauth2/… appid、secret、code 和 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. 获取用户信息(可选)

拿到 access_token 和 openid 后,调用 api.weixin.qq.com/sns/userinf… 可以获取昵称、头像等信息:

String userInfoUrl = "https://api.weixin.qq.com/sns/userinfo" +
    "?access_token=" + accessToken +
    "&openid=" + openId;
// 解析返回的 JSON,得到 nickname、headimgurl 等字段

两个关键的安全与设计要点

① 必须校验 state 参数

state 用于防止 CSRF 攻击。在生成授权链接前,服务端应生成一个随机值(如 UUID)并存入当前会话(Session 或 Redis);回调时,必须校验微信回传的 state 与会话中保存的值一致,否则拒绝登录。

② openid 是网站应用内的唯一标识

同一个用户在不同网站应用下的 openid 是不同的;但在同一个网站应用内,openid 是稳定且唯一的。本地用户表应以此字段作为微信登录的关联键,而不是依赖昵称或头像(它们可能被用户修改)。如果需要跨应用统一用户标识,则需使用 unionid(要求多个应用绑定在同一开放平台账号下)。


两种方式的选择

· 追求开发效率、项目已有 Spring 生态:选 WxJava。它帮你处理了 token 缓存、HTTP 错误、JSON 解析等细节,代码量少,维护成本低。 · 希望零外部依赖、需要完全掌控 HTTP 调用:选手动调用。适合对依赖敏感的项目,或需要深度定制请求/响应的场景。

无论哪种方式,微信官方的授权回调域必须提前配置且与实际回调地址严格匹配,这是接入时最常见的卡点。建议开发阶段先用内网穿透工具(如 ngrok)生成临时公网域名完成调试,上线前再切换到正式备案域名。