微信网页授权
需求:
- 能获取用户基本信息。
- 获取微信信息的时候,从哪个页面来,最后到哪个页面去。
- 调用方式要简单。
思路:
因为之前写过几次,思路还是很清楚的,大概有一下几个步骤:
- 提供一个链接,带有一个redirect_url参数,代表在获取用户信息后要返回的页面。
- 在上一个链接中跳转进行微信网页授权。
- 授权成功后获取code。
- 通过code调用微信接口获取access_token。
- 通过access_token获取用户基本信息。
- 将用户信息拼在之前定义的redirect_url中,并重定向到redirect_url。
实现:
思路有了下面就开始实现这个思路
1:
首先定义一个方法,接收redirect_url参数,并在这个方法中跳转到微信授权页面。
这里我们需要完成思路中1,2的步骤。
注意:
在浏览器中调用方法的时候redirect_url参数要经过 URLEncoder.encode
在方法中接收的redirect_url参数任然需要经过URLEncoder.encode
,因为在作为参数接收到的时候,这个参数已经变成正常的http链接了。
在拼装微信重定向地址的时候,需要再次URLEncoder.encode
。
//微信网页授权地址 private String getWechatCodeUrl = "https://open.weixin.qq.com/connect/oauth2/authorize?" + "appid=[APPID]&" + //微信appid "redirect_uri=[REDIRECT_URI]&" + //获取网页授权后,微信重定向地址 "response_type=code&" + "scope=snsapi_userinfo&" + //授权方式 "state=STATE#wechat_redirect"; //微信授权后返回的地址 private String getCodeUrl = "项目域名" + "redirect/code?redirect_url="; //提供的获取用户信息的地址 @GetMapping("/redirect") public String redirect( @RequestParam(name = "redirect_url", defaultValue = "", required = false) String redirectUrl ) throws UnsupportedEncodingException { //默认值,前端首页地址 if (StringUtils.isBlank(redirectUrl)) { redirectUrl = webSite; } //一次编码 redirectUrl = URLEncoder.encode(redirectUrl, "utf-8"); //二次编码 redirectUrl = URLEncoder.encode(getCodeUrl + redirectUrl, "utf-8"); //最终得到的微信获取微信授权地址 String url = getWechatCodeUrl .replace("[APPID]", appid) .replace("[REDIRECT_URI]", redirectUrl); logger.info("redirecturl: {}", url); return "redirect:" + url; }
2:
这里要在定义一个链接,就是上一步要让微信跳转回来的地址。这里微信会携带一个code参数,由于在上一步我们将redirect_url地址进行了两次编码,所以在这个方法中redirect_url也会传递进来。
着这个方法中我们需要完成思路中 4,5,6的步骤
//获取access_token的接口地址,这里还可以获取到openid private String getAccessTokenUrl = "https://api.weixin.qq.com/sns/oauth2/access_token?" + "appid=[APPID]&" + //微信的appid "secret=[SECRET]&" + //微信的secret "code=[CODE]&" + //重定向后微信携带的code参数 "grant_type=authorization_code"; //获取微信用户基本信息的接口地址 private String getWechatUserUrl = "https://api.weixin.qq.com/sns/userinfo?" + "access_token=[ACCESS_TOKEN]&" + //获取到的 access_token "openid=[OPENID]&" + //公众号的 openid "lang=zh_CN"; //这里的地址由微信重定向跳转,携带code参数。 @GetMapping("/redirect/code") public String getCode( @RequestParam(name = "redirect_url", defaultValue = "", required = false) String redirectUrl, @RequestParam(name = "code", defaultValue = "", required = false) String code ) throws UnsupportedEncodingException { logger.info("redirect_url: {}", redirectUrl); logger.info("code: {}", code); if (StringUtils.isBlank(code)) { logger.error("获取code失败"); return "redirect:" + redirectUrl + "?error=code-is-null"; } //解码重定向地址 redirectUrl = URLDecoder.decode(redirectUrl, "utf-8"); //根据code获取微信相关信息 String apiUrl = getAccessTokenUrl .replace("[APPID]", appid) .replace("[SECRET]", secret) .replace("[CODE]", code); String res = HttpUtils.doGet(apiUrl, new HashMap<>()); JSONObject resJson = JSONObject.parseObject(res); //请求失败 if (resJson.containsKey("errmsg")) { logger.error("获取access_token失败," + res); return "redirect:" + redirectUrl + "?error=" + resJson.getString("errmsg"); } //获取微信用户信息 String getUserUrl = getWechatUserUrl .replace("[ACCESS_TOKEN]", resJson.getString("access_token")) .replace("[OPENID]", resJson.getString("openid")); String user = HttpUtils.doGet(getUserUrl, new HashMap<>()); JSONObject userJson = JSONObject.parseObject(user); if (userJson.containsKey("errmsg")) { logger.error("获取access_token失败," + res); return "redirect:" + redirectUrl + "?error=" + userJson.getString("errmsg"); } //这里直接将微信用户信息编码后重定向给最开始的redirect_url return "redirect:" + redirectUrl + "?wechat_user=" + URLEncoder.encode(user, "utf-8"); }
完成:
这里就已经开发完成了,发布到线上后访问:
[域名]/redirect?redirect_url=[需要转到的地址]
后,在获得用户授权后会跳转
[需要转到的地址]?wechat_user=[URLEncoder.encode后的微信用户信息]
https://www.cnblogs.com/hebaibai/p/11089318.html
测试例子:
//微信网页授权官网 https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140842
public final String APPID ="APPID";//测试号appid
public final String APPSECRET =""; //测试号appsecret
//第一步:用户同意授权,获取code
public String GET_CODE_URL ="https://open.weixin.qq.com/connect/oauth2/authorize?" +
"appid=APPID" + //微信appid
"&redirect_uri=REDIRECT_URI" + //获取网页授权后,微信重定向地址
"&response_type=code" +
"&scope=snsapi_userinfo" + //授权方式
"&state=STATE#wechat_redirect";
//第二步:通过code换取网页授权access_token
public String ACCESS_TOKEN_URL="https://api.weixin.qq.com/sns/oauth2/access_token?" +
"appid=APPID" +
"&secret=SECRET" +
"&code=CODE" +
"&grant_type=authorization_code";
//第三步:刷新access_token(如果需要)
public String REFRESH_TOKEN_URL ="https://api.weixin.qq.com/sns/oauth2/refresh_token?" +
"appid=APPID" +
"&grant_type=refresh_token" +
"&refresh_token=REFRESH_TOKEN";
public String GET_USERINFO_URL="https://api.weixin.qq.com/sns/userinfo?" +
"access_token=ACCESS_TOKEN" +
"&openid=OPENID&lang=zh_CN";
//微信授权后返回的地址
private String getCodeUrl = "http://zw6kbz.natappfree.cc/studentApi/weChatAccounts";
//提供的获取用户信息的地址
@ResponseBody
@GetMapping("/redirect")
public void redirect(HttpServletResponse response,
@RequestParam(name = "redirect_url", defaultValue = "", required = false) String redirectUrl
) throws Exception {
//一次编码
redirectUrl = URLEncoder.encode(redirectUrl, "utf-8");
//二次编码
redirectUrl = URLEncoder.encode(getCodeUrl + redirectUrl, "utf-8");
//最终得到的微信获取微信授权地址
String url = GET_CODE_URL
.replace("APPID", APPID)
.replace("REDIRECT_URI", redirectUrl);
log.info("redirecturl: {}", url);
response.sendRedirect(url);
}
/**
*
* @param code
* @return
*/
@GetMapping("/weChatAccounts")
@ApiOperation("验证消息的确来自微信服务器")
public String weChatAccounts(@RequestParam(name = "code") String code,
HttpServletResponse response)
throws Exception {
Map<String,Object> map =new HashMap<>();
QrUser qrUser =new QrUser();
//第一步:用户同意授权,获取code
//第二步:通过code换取网页授权access_token
String access_token_url=ACCESS_TOKEN_URL.replace("APPID",APPID)
.replace("SECRET",APPSECRET)
.replace("CODE",code);
net.sf.json.JSONObject jsonObject = AuthUtil.doGetJson(access_token_url);
log.info(jsonObject.toString());
//获取access_token
String access_token=(String)jsonObject.get("access_token");
//获取openid
String openid=(String)jsonObject.get("openid");
//--------------------------逻辑判断------------------------------------------
//根据openid获取用户
QueryWrapper<QrUser> wrapper =new QueryWrapper<>();
wrapper.eq("open_id",openid);
QrUser user = qrUserService.getOne(wrapper);
net.sf.json.JSONObject userinfo=null;
String token=null;
String is_perfect="0";
if(user != null){
//生成token
token = JwtUtil.sign(user.getUserName(), user.getPassWord());
//map.put("success","用户已存在,直接登陆");
//map.put("user",user);
//map.put("is_perfect",user.getIsPerfect());
//System.out.println(user.getIsPerfect());
//System.out.println(user.getIsPerfect());
//is_perfect=user.getIsPerfect();
}else{
String get_userinfo_url = GET_USERINFO_URL.replace("ACCESS_TOKEN",access_token)
.replace("OPENID",openid);
userinfo = AuthUtil.doGetJson(get_userinfo_url);
//随机生成用户名
SimpleDateFormat sdf = new SimpleDateFormat("yyyyHHddHHmmss");
String Number =""+ sdf.format(new Date());//会员编号,不能重复
String str = "U" + Number;
qrUser.setUserName(str);
qrUser.setOpenId(openid);
qrUser.setNickName((String)jsonObject.get("nickname"));
qrUser.setImgUrl((String)jsonObject.get("headimgurl"));
qrUser.setAreaText((String)jsonObject.get("province")+","+(String)jsonObject.get("city"));
qrUser.setPassWord("123456");
qrUserService.save(qrUser);
//生成token
token = JwtUtil.sign(qrUser.getUserName(), qrUser.getPassWord());
//map.put("user",qrUser);
//map.put("success","用户第一次登陆,信息保存在数据库");
//map.put("is_perfect",0);
}
System.err.println("token:"+token);
redisUtil.set(CommonConstant.PREFIX_USER_TOKEN + token, token);
//设置超时时间
redisUtil.expire(CommonConstant.PREFIX_USER_TOKEN + token, JwtUtil.EXPIRE_TIME/1000);
map.put("token",token);
//-------------------------------------逻辑判断结束----------------------------------------
//第三步:刷新access_token(如果需要)
/*String refresh_token_url=REFRESH_TOKEN_URL.replace("APPID",APPID)
.replace("refresh_token",(String)jsonObject.get("refresh_token"));*/
//第四步:拉取用户信息(需scope为 snsapi_userinfo)
//return "redirect:/studentApi/token?token="+token;
return "redirect:http://www.baidu.com";//跳转百度表示成功
}