├── src └── main │ ├── resources │ └── application.yml │ └── java │ └── net │ └── ameizi │ ├── WeChatApplication.java │ ├── config │ ├── WeChatAppConfig.java │ └── WeChatMpConfig.java │ └── controller │ └── WechatController.java ├── .gitignore ├── README.md └── pom.xml /src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | wechat: 2 | appId: appId 3 | appSecret: appSecret 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .classpath 2 | .project 3 | .springBeans 4 | .settings/ 5 | target/ 6 | *.iml 7 | .idea/ -------------------------------------------------------------------------------- /src/main/java/net/ameizi/WeChatApplication.java: -------------------------------------------------------------------------------- 1 | package net.ameizi; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class WeChatApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(WeChatApplication.class, args); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/net/ameizi/config/WeChatAppConfig.java: -------------------------------------------------------------------------------- 1 | package net.ameizi.config; 2 | 3 | import lombok.Data; 4 | import org.springframework.boot.context.properties.ConfigurationProperties; 5 | import org.springframework.context.annotation.Configuration; 6 | 7 | @Data 8 | @Configuration 9 | @ConfigurationProperties(prefix = "wechat") 10 | public class WeChatAppConfig { 11 | 12 | private String appId; 13 | 14 | private String appSecret; 15 | 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/net/ameizi/config/WeChatMpConfig.java: -------------------------------------------------------------------------------- 1 | package net.ameizi.config; 2 | 3 | import me.chanjar.weixin.mp.api.WxMpConfigStorage; 4 | import me.chanjar.weixin.mp.api.WxMpInMemoryConfigStorage; 5 | import me.chanjar.weixin.mp.api.WxMpService; 6 | import me.chanjar.weixin.mp.api.impl.WxMpServiceImpl; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.context.annotation.Bean; 9 | import org.springframework.stereotype.Component; 10 | 11 | @Component 12 | public class WeChatMpConfig { 13 | 14 | @Autowired 15 | private WeChatAppConfig weChatAppConfig; 16 | 17 | @Bean 18 | public WxMpService wxMpService() { 19 | WxMpService wxMpService = new WxMpServiceImpl(); 20 | wxMpService.setWxMpConfigStorage(wxMpConfigStorage()); 21 | return wxMpService; 22 | } 23 | 24 | @Bean 25 | public WxMpConfigStorage wxMpConfigStorage() { 26 | WxMpInMemoryConfigStorage wxMpConfigStorage = new WxMpInMemoryConfigStorage(); 27 | wxMpConfigStorage.setAppId(weChatAppConfig.getAppId()); 28 | wxMpConfigStorage.setSecret(weChatAppConfig.getAppSecret()); 29 | return wxMpConfigStorage; 30 | } 31 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # springboot-weixin-mp 2 | 3 | SpringBoot整合weixin-java-tools实现微信公众号登录授权 4 | 5 | 注册 `https://ngrok.com` 将本地服务端口代理映射到公网,微信服务器端绑定映射到ngrok的域名进行调试 6 | 7 | ```bash 8 | wget https://bin.equinox.io/c/4VmDzA7iaHb/ngrok-stable-windows-amd64.zip 9 | 10 | unzip ngrok-stable-windows-amd64.zip 11 | 12 | ngrok authtoken 8TAZn4p5inht6MUKtkPzJ_6Amr8yEUYu6ZBndQ2CCKS 13 | 14 | ngrok http 8080 15 | 16 | ngrok by @inconshreveable (Ctrl+C to quit) 17 | 18 | Session Status online 19 | Account 冯靖 (Plan: Free) Fo 20 | rsion 2.3.27 Re 21 | gion United States (us) We 22 | b Interface http://127.0.0.1:4040 23 | Forwarding http://441aca54.ngrok.io -> http://localhost:8080 24 | Forwarding https://441aca54.ngrok.io -> http://localhost:8080 25 | 26 | Connections ttl opn rt1 rt5 p50 p90 27 | 0 0 0.00 0.00 0.00 0.00 28 | ``` 29 | 30 | 启动项目,将本地8080代理到441aca54.ngrok.io的80端口,在微信服务器端设置该域名后访问`https://441aca54.ngrok.io/wechat/authorize?returnUrl=http://baidu.com`即可获取微信用户信息 31 | 32 | 参考项目 33 | 34 | https://github.com/wechat-group/WxJava 35 | 36 | https://github.com/binarywang/weixin-java-mp-demo-springboot 37 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | net.ameizi 7 | springboot-weixin-mp 8 | 1.0 9 | jar 10 | 11 | springboot-weixin-mp 12 | Demo project for Spring Boot 13 | 14 | 15 | org.springframework.boot 16 | spring-boot-starter-parent 17 | 2.1.0.RELEASE 18 | 19 | 20 | 21 | 22 | UTF-8 23 | UTF-8 24 | 1.8 25 | 26 | 27 | 28 | 29 | org.springframework.boot 30 | spring-boot-starter-web 31 | 32 | 33 | 34 | org.projectlombok 35 | lombok 36 | true 37 | 38 | 39 | 40 | com.github.binarywang 41 | weixin-java-mp 42 | 3.3.0 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | org.springframework.boot 51 | spring-boot-maven-plugin 52 | 53 | 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /src/main/java/net/ameizi/controller/WechatController.java: -------------------------------------------------------------------------------- 1 | package net.ameizi.controller; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | import me.chanjar.weixin.common.api.WxConsts; 5 | import me.chanjar.weixin.common.error.WxErrorException; 6 | import me.chanjar.weixin.mp.api.WxMpService; 7 | import me.chanjar.weixin.mp.bean.result.WxMpOAuth2AccessToken; 8 | import me.chanjar.weixin.mp.bean.result.WxMpUser; 9 | import org.springframework.beans.factory.annotation.Autowired; 10 | import org.springframework.stereotype.Controller; 11 | import org.springframework.web.bind.annotation.GetMapping; 12 | import org.springframework.web.bind.annotation.RequestMapping; 13 | import org.springframework.web.bind.annotation.RequestParam; 14 | 15 | import java.net.URLEncoder; 16 | 17 | @Slf4j 18 | @Controller 19 | @RequestMapping("/wechat") 20 | public class WechatController { 21 | 22 | @Autowired 23 | private WxMpService wxMpService; 24 | 25 | /** 26 | * 请求微信服务器认证授权 27 | * 28 | * @param returnUrl 微信认证授权时的state参数 29 | * @return 30 | */ 31 | @GetMapping("/authorize") 32 | public String authorize(@RequestParam("returnUrl") String returnUrl) { 33 | // 用户授权完成后的重定向链接,441aca54.ngrok.io为使用ngrok代理后的公网域名,该域名需要替换为在微信公众号后台设置的域名,否则请求微信服务器不成功,一般都是采用将本地服务代理映射到一个可以访问的公网进行开发调试 34 | String url = "https://441aca54.ngrok.io/wechat/userInfo"; 35 | String redirectURL = wxMpService.oauth2buildAuthorizationUrl(url, WxConsts.OAuth2Scope.SNSAPI_USERINFO, URLEncoder.encode(returnUrl)); 36 | log.info("【微信网页授权】获取code,redirectURL={}", redirectURL); 37 | return "redirect:" + redirectURL; 38 | } 39 | 40 | /** 41 | * 认证授权成功后返回微信用户信息 42 | * 43 | * @param code 微信授权成功后重定向地址后的code参数 44 | * @param returnUrl 请求微信授权时携带的state参数 45 | * @return 46 | * @throws Exception 47 | */ 48 | @GetMapping("/userInfo") 49 | public String userInfo(@RequestParam("code") String code, 50 | @RequestParam("state") String returnUrl) throws Exception { 51 | log.info("【微信网页授权】code={}", code); 52 | log.info("【微信网页授权】state={}", returnUrl); 53 | WxMpOAuth2AccessToken wxMpOAuth2AccessToken; 54 | try { 55 | // 获取accessToken 56 | wxMpOAuth2AccessToken = wxMpService.oauth2getAccessToken(code); 57 | } catch (WxErrorException e) { 58 | log.error("【微信网页授权】{}", e); 59 | throw new Exception(e.getError().getErrorMsg()); 60 | } 61 | // 根据accessToken获取openId 62 | String openId = wxMpOAuth2AccessToken.getOpenId(); 63 | log.info("【微信网页授权】openId={}", openId); 64 | // 获取用户信息 65 | WxMpUser wxMpUser = wxMpService.oauth2getUserInfo(wxMpOAuth2AccessToken, null); 66 | log.info("【微信网页授权】wxMpUser={}", wxMpUser); 67 | // 刷新accessToken 68 | wxMpService.oauth2refreshAccessToken(wxMpOAuth2AccessToken.getRefreshToken()); 69 | // 验证accessToken是否有效 70 | wxMpService.oauth2validateAccessToken(wxMpOAuth2AccessToken); 71 | return "redirect:" + returnUrl + "?openid=" + openId; 72 | } 73 | } 74 | --------------------------------------------------------------------------------