java实现微信扫码登录第三方网站功能(原理和代码)
人气:0为避免繁琐的注册登陆,很多平台和网站都会实现三方登陆的功能,增强用户的粘性。这篇文章主要介绍了java实现微信扫码登录第三方网站功能(原理和代码),避免做微信登录开发的朋友们少走弯路。
一.查看微信扫码登录官方文档
1.在进行第三方授权登录之前,需要在微信开放平台注册开发者账号,拿到相应的AppId和AppSecret以及redirect_uri,即可进行授权接入流程;
2.第三方可以获取到用户的接口调用凭证(access_token),通过access_token可以进行微信开放平台授权关系接口调用,从而可实现获取微信用户基本开放信息和帮助用户实现基础开放功能等。
获取access_token时序图:
二.实现微信第三方登录流程:
1. 开发者调用微信接口用于获取扫描二维码。
调用接口:
参数介绍:
appid: 微信申请已存在的服务号的应用号;
redirect_uri: 回调地址,扫完码之后微信会将code这个值传到这个地址上,注意:回调地址需要用urlEncode处理;
responseType: 填code;
scope: 网页应用仅填snsapi_login;
state: 用于保持请求和回调的状态,授权请求后原样带给第三方,可用于防止跨站攻击;
2. 用户扫描二维码后该接口会自动返回重定向的资源上,并且带上code和state参数,如果用户拒绝授权只会带上state参数
3. 开发者通过用微信另一个接口根据code和 appid,secret获取access_token(也就是调用接口的凭证,有了他可以获取里面的openid等信息)
调用接口:
https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code
- 参数介绍
appid: 微信申请已存在的服务号的应用号;
secret:微信申请已存在的应用密匙;
code:调用上面一个接口自动返回的临时票据。
grant_type:写authorization_code
返回参数介绍
示例: { "access_token":"ACCESS_TOKEN", "expires_in":7200, "refresh_token":"REFRESH_TOKEN", "openid":"OPENID", "scope":"SCOPE" }
access_token:接口调用凭证
expires_in:access_token接口调用凭证超时时间,单位(秒)
refresh_token: 用户刷新access_token
openid:授权用户唯一标识(常用)
scope:用户授权的作用域
4.调用接口根据access_token和openid获取个人用户信息
调用接口:
http请求方式: GET
https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID
access_token:上个接口调用后返回的调用凭证
openid:上个接口获取的授权用户唯一标识返回参数介绍
示例; { "openid":"OPENID", "nickname":"NICKNAME", "sex":1, "province":"PROVINCE", "city":"CITY", "country":"COUNTRY", "headimgurl": "http://wx.qlogo.cn/mmopen/g3MonUZtNHkdmzicIlibx6iaFqAc56vxLSUfpb6n5WKSYVY0ChQKkiaJSgQ1dZuTOgvLLrhJbERQQ4eMsv84eavHiaiceqxibJxCfHe/0", "privilege":["PRIVILEGE1","PRIVILEGE2"], "unionid": " o6_bmasdasdsad6_2sgVt7hMZOPfL" }
openid:授权用户唯一标识
nickname:普通用户昵称
sex:普通用户性别,1为男性,2为女性
province:普通用户个人资料填写的省份
city:普通用户个人资料填写的城市
country:国家,如中国为CN
headimgurl:用户头像,最后一个数值代表正方形头像大小(有0、46、64、96、132数值可选,0代表640*640正方形头像),用户没有头像时该项为空
privilege:用户特权信息,json数组,如微信沃卡用户为(chinaunicom)
unionid:用户统一标识。针对一个微信开放平台帐号下的应用,同一用户的unionid是唯一的。
三.代码实现:
1.创建相关工具类
封装的几个基础类
a. access_token封装基础类
public class Token { private String openid; //授权用户唯一标识 private String accessToken; //接口调用凭证 private Integer ExpiresIn; //access_token接口调用凭证超时时间,单位(秒) public String getOpenid() { return openid; } public void setOpenid(String openid) { this.openid = openid; } public String getAccessToken() { return accessToken; } public void setAccessToken(String accessToken) { this.accessToken = accessToken; } public Integer getExpiresIn() { return ExpiresIn; } public void setExpiresIn(Integer expiresIn) { ExpiresIn = expiresIn; }
b. 根据openid获取用户信息封装成基础类
public class WechatUserInfo { private String unionid; //用户唯一标识 private String nickname; //昵称 private String headimgurl; //头像地址 private String subscribe; // 用户是否订阅该公众号标识,值为0时,代表此用户没有关注该公众号,拉取不到其余信息。 1 用户已经绑定公众号 public String getUnionid() { return unionid; } public void setUnionid(String unionid) { this.unionid = unionid; } public String getNickname() { return nickname; } public void setNickname(String nickname) { this.nickname = nickname; } public String getHeadimgurl() { return headimgurl; } public void setHeadimgurl(String headimgurl) { this.headimgurl = headimgurl; } public String getSubscribe() { return subscribe; } public void setSubscribe(String subscribe) { this.subscribe = subscribe; }
工具类
a. urlEncodeUTF8工具类(用于将扫描二维码后重定向的资源url进行编码)
public static String urlEncodeUTF8(String source){ String result = source; try { result = java.net.URLEncoder.encode(source,"utf-8"); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } return result; }
b. httpsRequest工具类(用于处理微信的获取openid和用户信息的接口的请求调用,返回相应的数据)
/** * 发送https请求 * @param requestUrl 请求地址 * @param requestMethod 请求方式(GET、POST) * @param outputStr 提交的数据 * @return 返回微信服务器响应的信息 */ public static String httpsRequest(String requestUrl, String requestMethod, String outputStr) { try { // 创建SSLContext对象,并使用我们指定的信任管理器初始化 TrustManager[] tm = { new MyX509TrustManager() }; SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE"); sslContext.init(null, tm, new java.security.SecureRandom()); // 从上述SSLContext对象中得到SSLSocketFactory对象 SSLSocketFactory ssf = sslContext.getSocketFactory(); URL url = new URL(requestUrl); HttpsURLConnection conn = (HttpsURLConnection) url.openConnection(); conn.setSSLSocketFactory(ssf); conn.setDoOutput(true); conn.setDoInput(true); conn.setUseCaches(false); // 设置请求方式(GET/POST) conn.setRequestMethod(requestMethod); conn.setRequestProperty("content-type", "application/x-www-form-urlencoded"); // 当outputStr不为null时向输出流写数据 if (null != outputStr) { OutputStream outputStream = conn.getOutputStream(); // 注意编码格式 outputStream.write(outputStr.getBytes("UTF-8")); outputStream.close(); } // 从输入流读取返回内容 InputStream inputStream = conn.getInputStream(); InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8"); BufferedReader bufferedReader = new BufferedReader(inputStreamReader); String str = null; StringBuffer buffer = new StringBuffer(); while ((str = bufferedReader.readLine()) != null) { buffer.append(str); } // 释放资源 bufferedReader.close(); inputStreamReader.close(); inputStream.close(); inputStream = null; conn.disconnect(); return buffer.toString(); } catch (ConnectException ce) { log.error("连接超时:{}", ce); } catch (Exception e) { log.error("https请求异常:{}", e); } return null; }
c. 获取openid等信息的方法
public static Token getTokenWithOpenid(String appid, String appsecret, String code) { String findAccessTokenUrl = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code"; Token token = null; String requestUrl = findAccessTokenUrl.replace("APPID", appid).replace("SECRET", appsecret).replace("CODE", code);// 发起GET请求获取凭证 JSONObject jsonObject = JSONObject.fromObject(httpsRequest(requestUrl, "GET", null)); if (null != jsonObject) { try { token = new Token(); token.setOpenid(jsonObject.getString("openid")); token.setAccessToken(jsonObject.getString("access_token")); token.setExpiresIn(jsonObject.getInt("expires_in")); } catch (JSONException e) { token = null; // 获取token失败 log.error("获取token失败 errcode:{} errmsg:{}", jsonObject.getInt("errcode"), jsonObject.getString("errmsg")); } } return token; }
d. 根据openid获取用户信息的方法
public static WechatUserInfo getUserinfo(String access_token, String openid) { WechatUserInfo wxuse = new WechatUserInfo(); String findUseinfo = "https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID"; String requestUrl = findUseinfo.replace("ACCESS_TOKEN", access_token).replace("OPENID", openid); JSONObject jsonObject = JSONObject.fromObject(httpsRequest(requestUrl, "GET", null)); if (null != jsonObject) { try { wxuse.setNickname(jsonObject.getString("nickname")); wxuse.setHeadimgurl(jsonObject.getString("headimgurl")); wxuse.setUnionid(jsonObject.getString("unionid")); } catch (JSONException e) { e.printStackTrace(); } } return wxuse; }
操作:
a. 跳转至登录授权页面(页面出现二维码)
public String weChatLanded(){ String requestUrl = "https://open.weixin.qq.com/connect/qrconnect?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE"; String loginAppid = "wxea43f181e32e8df0"; //微信申请的appid String loginRedirectUrl = "https://www.qb5200.com/weChatLogin_epf.action";//调用微信接口后返回的资源名 String loginScope = "snsapi_login";//写死 redirectURL = requestUrl.replace("APPID", loginAppid).replace("REDIRECT_URI", CommonUtil.urlEncodeUTF8(loginRedirectUrl)).replace("SCOPE", loginScope); return SUCCESS; }
b. 授权成功后:
@SuppressWarnings("static-access") public String weChatLogin_epf(){ //通过code获取access_token String loginAppid = "wxea43f181e32e8df0"; String loginSecrect = "4721e5f744e6c0f3c4094b25449ee7e3"; Token tokenWithOpenid = CommonUtil.getTokenWithOpenid(loginAppid, loginSecrect,code); String openid = tokenWithOpenid.getOpenid(); String access_token = tokenWithOpenid.getAccessToken(); //通过access_token调用接口 WechatUserInfo wxuse = CommonUtil.getUserinfo(access_token, openid); return SUCCESS; }
加载全部内容