本文主要针对微信公众号(公众平台的开发)
首先理解一个概念:OAuth:
OAuth(开放授权)是一个开放标准,允许用户让第三方应用访问该用户在某一网站上存储的私密的资源(如照片,视频,联系人列表),而无需将用户名和密码提供给第三方应用。
在本篇文章中模拟用户在微信公众号中使用OAuth进行授权,从而使第三方应用拿到用户的部分信息。
详细的开发文档可查看微信的官方文档 https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/Wechat_webpage_authorization.html
首先由于本人没有企业级微信公众账号,所以利用个人微信申请了微信公众账号的一个测试号,申请步骤如下:
进入测试号之后,系统会分配一个appleID和appsecret(可以用于在开发项目的yml文件中配置)
![99a82386e7fe03af2b057c41764adc3a.png](https://i-blog.csdnimg.cn/blog_migrate/8fd198c02eabaa3d3a0e3d4e8c53d974.png)
接着需要配置接口信息,由于微信开发需要公网才能被访问到,因此需要将内网穿透到外网才能保证接口可访问性。
natapp地址:
NATAPP -natapp.cn![68c0433728629cce316d7fb137425255.png](https://i-blog.csdnimg.cn/blog_migrate/69c9e5ecffb00ab0ad599ac21d1d442c.jpeg)
由于免费隧道每次映射的ip会发生变化,所以建议购买VIP隧道(大概加上二级域名12元/月?)买完之后你会拿到一个authtoken。
然后下载natapp文件,使用终端cd到natapp所在的文件夹下,利用:
#进行授权操作
$ chmod a+x natapp
# 在natapp文件的当前路径运行
$ ./natapp -authtoken={此处填写authtoken值}
显示如下则配置成功:
![086d82272ae68d328a0bdc59bf295c98.png](https://i-blog.csdnimg.cn/blog_migrate/8ddf98eada010a7fa3e46e0e5ba6c29f.jpeg)
这样以后就可以继续配置测试号中的接口了,现在来说说接口信息中的URL和token到底是什么。
简单地说就是微信测试号需要通过请求一个URL来相应token验证,也就是说你在点击确定时向你指定的URL发送一个请求,在请求里面来验证你的token是否一致。完成此验证之后,微信才能进行调用这个外网服务器端口。所以需要编写一个借口放在服务器上面:
SpringBoot代码如下:
@RequestMapping("/wechat")
@Controller
public class TestnatappController {
private static Logger logger = Logger.getLogger(TestnatappController.class);
private static String WECHAT_TOKEN = "DQicy";
@RequestMapping(value = "/wx.do")
public void get(HttpServletRequest request, HttpServletResponse response) throws Exception {
logger.error("WechatController ---- WechatController");
System.out.println("========WechatController========= ");
logger.info("请求进来了...");
Enumeration pNames = request.getParameterNames();
while (pNames.hasMoreElements()) {
String name = (String) pNames.nextElement();
String value = request.getParameter(name);
// out.print(name + "=" + value);
String log = "name =" + name + " value =" + value;
logger.error(log);
}
String signature = request.getParameter("signature");/// 微信加密签名
String timestamp = request.getParameter("timestamp");/// 时间戳
String nonce = request.getParameter("nonce"); /// 随机数
String echostr = request.getParameter("echostr"); // 随机字符串
PrintWriter out = response.getWriter();
//if (SignUtil.checkSignature(signature, timestamp, nonce)) {
out.print(echostr);
// }s
out.close();
// out = null;
}
}
注意将程序中的token换成和你想要配置的token一致即可。然后url就可以写成你原先配置的外网/wechat/wx.do的形式,即可验证通过。
继续配置回调函数:
![9fca6388eb3b471f53e54a99cc21981b.png](https://i-blog.csdnimg.cn/blog_migrate/fe6d03fe0e84f103d25b95d1f36a4320.jpeg)
回调函数用于当我们在微信客户端访问第三方应用的时候,首先通过微信网页授权机制获取到用户授权的信息后,通过回调的域名设置,页面还会进行再次跳转。所以配置为外网即可(注意去掉协议部分,即http://)。如果你的网址没有被列入黑名单,就会通过安全监测,就可以使用啦。
至此,域名的配置成功了。
然后进入授权部分,先看官方文档怎么说:
![5b0649d9e32039e81dcebb6304edc20b.png](https://i-blog.csdnimg.cn/blog_migrate/cf30e96efaebc4c3b7762011509719a3.jpeg)
两种方法:
1.手工获取openid
首先第一步:引导关注者打开https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect
其中appid替换为自己的标识信息,
redirect_uri填上要跳转的连接,
scope是应用授权的作用域,有两种选择(根据不同需要作出不同选择):
(1)snsapi_base:这种方式可以直接获取用户的少量信息,不弹出授权的页面
(2)snsapi_userinfo: 这种方式需要用户点击确认按键,但是可以通过openid拿到更多用户的信息
response_type设置为code即可。
如果用户同意授权,页面将跳转至 redirect_uri/?code=CODE&state=STATE。也就是说返回的url中会拿到code值,于是在项目中补上controller来接收用户的code值(code值有效期只有5分钟)
控制器代码如下:
package com.imooc.controller;
@RestController
@RequestMapping("/weixin")
@Slf4j
public class WeixinController {
@GetMapping("/auth")
public void auth(@RequestParam("code") String code) {
log.info("进入auth方法...");
log.info("code={}", code);
}
}
在auth方法中接收url返回的code值通过手机测试,可以在console输出code的值。
第二步:通过code换取网页授权的access_token
![36fc52f86419d3734a7af8ae93b7e7e6.png](https://i-blog.csdnimg.cn/blog_migrate/33c5f816a5eea4c4476939460452777d.jpeg)
![f4a91e8648ee120d182d6218af836001.png](https://i-blog.csdnimg.cn/blog_migrate/79378ae4ba64bfb0d40f15fd1ae82156.jpeg)
根据官方说明,用code换取access_token的过程实际上是返回一个json格式的数据。
接着测试:
String url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=wx45ea7710b15596a9&secret=0dffebbdf4591d3de7f76ebc08d5f13d&code=" + code + "&grant_type=authorization_code";
RestTemplate restTemplate = new RestTemplate();
String response = restTemplate.getForObject(url,String.class);
log.info("response={}",response);
response即为包含access_token的json数据,其中包含后面会用到的openid。
2.利用第三方SDK
github地址:
https://github.com/Pay-Group/best-pay-sdkgithub.com用之前先在pom.xml中引入依赖,再看网页授权部分的操作:
https://github.com/Wechat-Group/WxJava/wiki/MP_OAuth2%E7%BD%91%E9%A1%B5%E6%8E%88%E6%9D%83github.com首先配置WxService:
@Data
@Component
//下面注解的作用:spring-boot 提供该注解将配置文件的值映射到类上使用
@ConfigurationProperties(prefix = "wechat")
public class WechatAccountConfig {
//公众平台Id
private String mpAppId;
//公众平台密钥
private String mpAppSecret;
}
在MpConfig文件中引用配置的account:
@Component
public class WechatMpConfig {
@Autowired
private WechatAccountConfig accountConfig;
@Bean
public WxMpService wxMpService(){
WxMpService wxMpService = new WxMpServiceImpl();
wxMpService.setWxMpConfigStorage(wxMpConfigStorage());
return wxMpService;
}
@Bean
public WxMpConfigStorage wxMpConfigStorage() {
WxMpInMemoryConfigStorage wxMpConfigStorage = new WxMpInMemoryConfigStorage();
wxMpConfigStorage.setAppId(accountConfig.getMpAppId());
wxMpConfigStorage.setSecret(accountConfig.getMpAppSecret());
return wxMpConfigStorage;
}
}
然后写控制器类:
@Controller
@RequestMapping("/wechat")
@Slf4j
public class WechatController {
@Autowired
private WxMpService wxMpService;
@GetMapping("/authorize")
public String authorize(@RequestParam("returnUrl") String returnUrl){
//1.配置
//2.调用方法 (重定向)
String url = "http://.../sell/wechat/userInfo";
String redirectUrl = wxMpService.oauth2buildAuthorizationUrl(url,WxConsts.OAUTH2_SCOPE_BASE, URLEncoder.encode(returnUrl));
log.info("[微信网页授权] 获得code, result={}", redirectUrl);
return "redirect:" + redirectUrl ;
}
//下面为重定向后到达的方法
@GetMapping("/userInfo")
public String userInfo(@RequestParam("code") String code,
@RequestParam("state") String returnUrl){
WxMpOAuth2AccessToken wxMpOAuth2AccessToken = new WxMpOAuth2AccessToken();
try {
wxMpOAuth2AccessToken = wxMpService.oauth2getAccessToken(code);
}catch (WxErrorException e){
log.error("[微信网页授权] {}",e);
throw new SellException(ResultEnum.WECHAT_MP_ERROR.getCode() , e.getError().getErrorMsg());
}
return "redirect:" + returnUrl + "?openid=" + openId;
}
}
通过获取code,再通过获取access_token的方式即可获得用户的openid。
以上为两种微信授权登录的常用方式。