1. 前期准备
网站应用微信登录是基于OAuth2.0协议标准构建的微信OAuth2.0授权登录系统。 在进行微信OAuth2.0授权登录接入之前,在微信开放平台(https://open.weixin.qq.com)注册开发者帐号,并拥有一个已审核通过的网站应用,并获得相应的 AppID 和AppSecret,申请微信登录且通过审核后,可开始接入流程。
2. 授权流程
微信OAuth2.0授权登录让微信用户使用微信身份安全登录第三方应用或网站,在微信用户授权登录已接入微信OAuth2.0的第三方应用后,第三方可以获取到用户的接口调用凭证(access_token),通过access_token可以进行微信开放平台授权关系接口调用,从而可实现获取微信用户基本开放信息和帮助用户实现基础开放功能等。
(1) 第三方发起微信授权登录请求,微信用户允许授权第三方应用后,微信会拉起应用或重定向到第三方网站,并且带上授权临时票据 code 参数;
(2)通过 code 参数加上 AppID 和AppSecret等,通过 API 换取access_token;
(3)通过access_token进行接口调用,获取用户基本数据资源或帮助用户实现基本操作。
3. 首先生成微信登录二维码
(1)前端引入JS文件,在需要使用微信登录的地方实例化JS对象
(2)后端返回相应的参数值
在application-dev.yml添加配置
wx.open.app_id=wxed9954c01bb89b47
wx.open.app_secret=a7482517235173ddb4083788de60b90e
wx.open.redirect_url=http://localhost:8160/api/ucenter/wx/callback
yygh.baseUrl=http://localhost:3000
添加接口
//微信操作的接口 @Controller @RequestMapping("/api/ucenter/wx") public class WeixinApiController { //1. 生成微信二维码 @GetMapping("getLoginParam") @ResponseBody public Result genQrConnect() { try { Map<String, Object> map = new HashMap<>(); map.put("appid", ConstantWxPropertiesUtils.WX_OPEN_APP_ID); map.put("scope","snsapi_login"); String url = ConstantWxPropertiesUtils.WX_OPEN_REDIRECT_URL; String encode = URLEncoder.encode(url, "utf-8"); map.put("redirect_uri",encode); map.put("state",System.currentTimeMillis()+""); return Result.ok(map); } catch (UnsupportedEncodingException e) { e.printStackTrace(); return null; } } }
4. 手机扫码登录过程
(1)当使用手机扫码允许,用户允许授权后,将会重定向到redirect_uri的网址上,并且带上 code 和state参数。若用户禁止授权,则不会发生重定向。
redirect_uri?code=CODE&state=STATE
(2)通过 code 获取access_token和openid
https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code
(3)使用access_token和open_id,请求微信固定地址,得到扫描人信息
https://api.weixin.qq.com/sns/userinfo
具体接口实现
//微信扫描后回调的方法 @GetMapping("callback") public String callback(String code,String state) { //1. 获取临时票据code System.out.println(code); StringBuffer baseAccessTokenUrl = new StringBuffer() .append("https://api.weixin.qq.com/sns/oauth2/access_token") .append("?appid=%s") .append("&secret=%s") .append("&code=%s") .append("&grant_type=authorization_code"); String accessTokenUrl = String.format(baseAccessTokenUrl.toString(), ConstantWxPropertiesUtils.WX_OPEN_APP_ID, ConstantWxPropertiesUtils.WX_OPEN_APP_SECRET, code); //2. 使用code和微信id和密钥,请求微信固定地址,获取access_token和open_id try { String accesstokenInfo = HttpClientUtils.get(accessTokenUrl); System.out.println(accesstokenInfo); JSONObject jsonObject = JSONObject.parseObject(accesstokenInfo); String access_token = jsonObject.getString("access_token"); String openid = jsonObject.getString("openid"); //判断数据库是否存在微信的扫描人信息 //根据openid判断 UserInfo userInfo = userInfoService.selectWxInfoOpenId(openid); if (userInfo == null){ //3. 使用access_token和open_id,请求微信固定地址,得到扫描人信息 String baseUserInfoUrl = "https://api.weixin.qq.com/sns/userinfo" + "?access_token=%s" + "&openid=%s"; String userInfoUrl = String.format(baseUserInfoUrl, access_token, openid); String resultInfo = HttpClientUtils.get(userInfoUrl); System.out.println("resultInfo" + resultInfo); JSONObject resultUserInfoJson = JSONObject.parseObject(resultInfo); //解析用户信息 //用户昵称 String nickname = resultUserInfoJson.getString("nickname"); //用户头像 String headimgurl = resultUserInfoJson.getString("headimgurl"); //获取扫描人信息添加到数据库中 userInfo = new UserInfo(); userInfo.setNickName(nickname); userInfo.setOpenid(openid); userInfo.setStatus(1); userInfoService.save(userInfo); } //返回name和token字符串 Map<String,String> map = new HashMap<>(); String name = userInfo.getName(); if(StringUtils.isEmpty(name)) { name = userInfo.getNickName(); } if(StringUtils.isEmpty(name)) { name = userInfo.getPhone(); } map.put("name", name); //判断userInfo是否有手机号,如果手机号为空,返回openId,如果不为空返回空字符串 //前端根据openid判断,如果为空不用绑定手机号,如果不为空要绑定手机号 if (StringUtils.isEmpty(userInfo.getPhone())){ map.put("openid",userInfo.getOpenid()); }else { map.put("openid",""); } String token = JwtHelper.createToken(userInfo.getId(), name); map.put("token",token); //跳转到前端页面 return "redirect:" + ConstantWxPropertiesUtils.YYGH_BASE_URL + "/weixin/callback?token="+map.get("token") + "&openid="+map.get("openid") +"&name="+URLEncoder.encode(map.get("name"),"utf-8"); } catch (Exception e) { e.printStackTrace(); return null; } }