微信授权的踩坑史 --基于springboot
最近在写一个javaweb的博客项目的时候,发现其中要使用到微信登录的功能,因为楼主之前并没有接触过微信登录的授权,结果花了很长时间,才弄出来了。其中踩雷踩坑也很多,希望在这里分享出来,让大家避免踩坑。
首先我们先通过微信官方的文档,来查看一下微信是如何进行授权的。微信的开发文档
微信授权,是可以通过测试号或者服务号来进行授权的,注意不是订阅号。订阅号是没有微信认证授权的功能的提供,当时我就是傻傻的去注册了一个订阅号。。。另外服务号每年是需要300块(好像是这么多),直接劝退。像我们这种贫民学生,还是使用测试号吧。。。测试号地址:微信测试号
在测试号里,我们要记住id和密码,下面代码会用到。
扫描二维码
找到网页授权这里,点击修改
输入你运行项目的外网地址。因为一般运行的项目都是通过本地8080端口查看的,而外网是看不到的,这时候我们需要有一个内网穿透的工具来把提供一个地址给微信。内网穿透的工具有很多,花生壳,nat等等。这个地址很重要,下面会讲到。
然后我们说说微信授权的流程,分为以下几步:
第一步:用户同意授权,获取code
需要的参数
返回的数据
第二步:通过code换取网页授权access_token
需要的参数:
返回的数据
第三步:刷新access_token(一般不用)
第四步:拉取用户信息(需scope为 snsapi_userinfo)
需要的参数
返回的数据:
一般来说,是不需要用到第三步的。所以我们步骤就是1,2,4。
我的理解是这样的:首先一开始,假如微信用户点击我们写好的请求地址,我们就会向微信发送一个请求,请求里,我们需要填入id,回应的地址,以及其他参数。然后微信收到后,就会给我们填的外网地址,发一个响应,所以如果你的地址没填对,你的响应是获取不到的。在这个相应里,我们可以得到code。得到code后,我们再通过微信发送一个请求,请求里我们填入id,密码,code,微信收到请求后,就会给我们发送一个响应,里面包括token,openid。openid是每个微信用户的唯一id。之后我们通过token和openid就可以访问每个登录用户的信息了。
可是使用测试号有个很大的缺点,就是登录之前必须得关注测试公众号,否则会提示你还未关注公众号,无法授权的。这个在服务号里就不用,是个坑。
下面是我使用springboot进行微信登录的实例。
1、引入第三方sdk
<dependency>
<groupId>com.github.binarywang</groupId>
<artifactId>weixin-java-mp</artifactId>
<version>2.8.0</version>
</dependency>
2、配置application.properties
wechat.appid=wxb3434252t0e886f13
wechat.secret=2df63d8798030t3438ddb1134400c
3、创建两个工具类,获取appid和secret
@Configuration
@PropertySource(value = "classpath:/application.properties")
public class WechatAccount {
@Value("${wechat.appid}")
private String appid;
@Value("${wechat.secret}")
private String secret;
public String getAppid() {
return appid;
}
public void setAppid(String appid) {
this.appid = appid;
}
public String getSecret() {
return secret;
}
public void setSecret(String secret) {
this.secret = secret;
}
}
@Component
public class Wechatmpconfig {
@Autowired
private WechatAccount account;
@Bean
public WxMpService wxMpService(){
WxMpService wxMpService=new WxMpServiceImpl();
wxMpService.setWxMpConfigStorage(wxConfigProvider());
return wxMpService;
}
@Bean
public WxMpConfigStorage wxConfigProvider(){
WxMpInMemoryConfigStorage wxConfigProvider=new WxMpInMemoryConfigStorage();
wxConfigProvider.setAppId(account.getAppid());
wxConfigProvider.setSecret(account.getSecret());
return wxConfigProvider;
}
}
4、编写一个controller
@Controller
@RequestMapping("/wechat")
public class Wechatcontroller {
@Autowired
private WxMpService wxMpService;
@Autowired
private Wechatservice wechatservice;
@RequestMapping("/attestation")
public Object attestation(){
return "attestation" ;
}
@GetMapping("/authorize")
public String authorize(@RequestParam("returnUrl") String returnUrl){
String url="http://codelong.natapp1.cc/wechat/userinfo";
String redirectURL=wxMpService.oauth2buildAuthorizationUrl(url, WxConsts.OAUTH2_SCOPE_USER_INFO, URLEncoder.encode(returnUrl));
System.out.println(redirectURL);
return "redirect:"+redirectURL;
}
@GetMapping("/userinfo")
public String userinfo(HttpServletRequest request, @RequestParam("code") String code, @RequestParam("state") String returnUrl) throws Exception{
WxMpOAuth2AccessToken wxMpOAuth2AccessToken=new WxMpOAuth2AccessToken();
try{
wxMpOAuth2AccessToken=wxMpService.oauth2getAccessToken(code);
}catch (WxErrorException e){
throw new Exception(e.getError().getErrorMsg());
}
System.out.println(wxMpOAuth2AccessToken);
String openid=wxMpOAuth2AccessToken.getOpenId();
WxMpUser wxMpUser=wxMpService.oauth2getUserInfo(wxMpOAuth2AccessToken,null);
return "redirect:"+returnUrl+"?openid="+openid;
}
}
最终效果: