微信扫码登录第三方网站

    一.先仔细研究一下微信扫码登录官方文档

    https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&id=open1419316505&token=&lang=zh_CN

    流程图:

     二.大致流程:

    1. 开发者调用微信接口用于获取扫描二维码。

  •  调用接口:

    https://open.weixin.qq.com/connect/qrconnect?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect

  •  参数介绍:
    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#wechat_redirect";
        String loginAppid = "wxea43f181e32e8df0";  //微信申请的appid
        String loginRedirectUrl = "https://www.homepin.cn/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;
        }

 

posted @ 2019-08-23 18:56  用飘柔的程序员  阅读(10016)  评论(0)    收藏  举报