微信开发之获取OAuth2.0网页授权认证和获取用户信息进行关联

标签: 微信 开发 oauth2.0 | 发表时间:2015-10-16 06:36 | 作者:
出处:http://www.iteye.com


        最近有做了关于微信公众号和自己网站用户进行用户关联授权登录的一个功能,主要是用户关注该公众号,点击会员中心,则会弹出需要关联授权的网页授权:OAuth2.0网页授权,然后用户同意获取用户信息,进行用户和网站的关联,然后用户则可以使用微信进行登录。

        本次做的是一个在Java的Action层处理各个返回参数获取数据。

       一、 使用到的工具:

            1、ngrok,将你自己的本机映射到公网,这样保证可以随时测试开发;

                   1、下载ngrok,网址: http://www.tunnel.mobi/

                   2、将文件放到Tomcat目录下,在cmd中运行ngrok -config ngrok.cfg -subdomain xinzhi 8080

                   3、ngrok工具为在慕课网@LAOBI 看到的

            2、微信公众号测试账号,随时测试,首先保证在测试账号下没有问题后在进行公众号的移植。

       二、使用到在Java中发送一个Http请求,然后返回JSON参数,获得JSON参数,然后进行处理。

           首先,获取将公众号测试号放到properties文件中,以便我们进行调用或者更换,如:url请用https

   

AppID = wxf00**c3dd2ebfa0
AppSecret = 3cb220755f****506dc35391aa5c03ec
url = https://xinzhi.tunnel.mobi

 

           这里url为我们映射到外网的地址,一会需要用到。然后需要两个工具类,该工具类作用是在Java的Action中发送http请求后获取到去返回值

            这里使用的是@ 柳峰,关于服务器请求的代码 http://blog.csdn.net/lyq8479/article/details/9841371,启用自己有相应的改动,以适应本项目的需求:

           WeixinUtil.java 和 MyX509TrustManager.java

 

package com.zhtx.common.util;


import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.ConnectException;
import java.net.URL;

import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;


import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


/**
 * 公众平台通用接口工具类
 * 
 * @author xinz
 * @date 2015-10-14
 */
public class WeixinUtil {
	private static Logger log = LoggerFactory.getLogger(WeixinUtil.class);

	/**
	 * 发起https请求并获取结果
	 * 
	 * @param requestUrl 请求地址
	 * @param requestMethod 请求方式(GET、POST)
	 * @param outputStr 提交的数据
	 * @return JSONObject(通过JSONObject.get(key)的方式获取json对象的属性值)
	 */
	public static String httpRequest(String requestUrl, String requestMethod, String outputStr) {
		StringBuffer buffer = new StringBuffer();
		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 httpUrlConn = (HttpsURLConnection) url.openConnection();
			httpUrlConn.setSSLSocketFactory(ssf);

			httpUrlConn.setDoOutput(true);
			httpUrlConn.setDoInput(true);
			httpUrlConn.setUseCaches(false);
			// 设置请求方式(GET/POST)
			httpUrlConn.setRequestMethod(requestMethod);

			if ("GET".equalsIgnoreCase(requestMethod))
				httpUrlConn.connect();

			// 当有数据需要提交时
			if (null != outputStr) {
				OutputStream outputStream = httpUrlConn.getOutputStream();
				// 注意编码格式,防止中文乱码
				outputStream.write(outputStr.getBytes("UTF-8"));
				outputStream.close();
			}

			// 将返回的输入流转换成字符串
			InputStream inputStream = httpUrlConn.getInputStream();
			InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8");
			BufferedReader bufferedReader = new BufferedReader(inputStreamReader);

			String str = null;
			while ((str = bufferedReader.readLine()) != null) {
				buffer.append(str);
			}
			bufferedReader.close();
			inputStreamReader.close();
			// 释放资源
			inputStream.close();
			inputStream = null;
			httpUrlConn.disconnect();
			
		} catch (ConnectException ce) {
			log.error("Weixin server connection timed out.");
		} catch (Exception e) {
			log.error("https request error:{}", e);
		}
		return buffer.toString();
	}
}

 

 对于https请求,我们需要一个证书信任管理器,这个管理器类需要自己定义,但需要实现X509TrustManager接口,代码如下:

 

package com.zhtx.common.util;


import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

import javax.net.ssl.X509TrustManager;

/**
 * 证书信任管理器(用于https请求)
 * 
 * @author xinz
 * @date 2015-10-14
 */
public class MyX509TrustManager implements X509TrustManager {

	public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
	}

	public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
	}

	public X509Certificate[] getAcceptedIssuers() {
		return null;
	}
}

 微信返回参数的一个POJO类:

 

  private String  openid;  //用户的唯一标识 
  private String  nickname;//用户昵称 
  private Integer sex;// 用户的性别,值为1时是男性,值为2时是女性,值为0时是未知 
  private String  province;//用户个人资料填写的省份 
  private String  city;//普通用户个人资料填写的城市 
  private String  country;// 国家,如中国为CN 
  private String  headimgurl;  // 用户头像,最后一个数值代表正方形头像大小(有0、46、64、96、132数值可选,0代表640*640正方形头像),用户没有头像时该项为空。若用户更换头像,原有头像URL将失效。 
  private String  privilege;// 用户特权信息,json 数组,如微信沃卡用户为(chinaunicom) 
  private String  unionid;// 只有在用户将公众号绑定到微信开放平台帐号后,才会出现该字段。详见:获取用户个人信息(UnionID机制) 
  private String access_token;

 

 授权凭证验证的类:

 

private String errcode;
private String errmsg;

 通过code换取网页授权access_token

 

	private String access_token;
	private String expires_in;
	private String refresh_token;
	private String openid;
	private String scope;
	private String unionid;

 关于微信头像的,获取的是一个http的url,则需要将图片下载到服务器存储,然后获得相对路径:

 

/**
	 * 使用url或者http存入文件
	 * @Title: fileUpload
	 * @param @param fileUrl  文件url,可以是http
	 * @param @param path     文件存储路径
	 * @return void
	 * @throws xinz
	 */
	public static void fileUpload (String fileUrl,String path){
		 //读取文件
		  String s1 = fileUrl;   
		  java.io.InputStream is = null; //定义一个输入流。
		  BufferedInputStream bis = null;//定义一个带缓冲的输入流 。 
		//写到本地 
		  BufferedOutputStream bos = null; //定义一个带缓冲的输出流。
		  try{ 
			java.net.URL url = new java.net.URL(s1);//创建一个URL对象。
		  	is = url.openStream();//打开到此 URL 的连接并返回一个用于从该连接读入的 InputStream。
		  	bis = new java.io.BufferedInputStream(is);     
		    File file = new File(path);   
			if(!file.exists()){ //测试此抽象路径名表示的文件或目录是否存在。  
				file.createNewFile();   //创建此抽象路径名表示的文件或目录。
			}   
		  bos = new BufferedOutputStream(new FileOutputStream(file));;     
		  byte[] b = new byte[1024]; //创建字节数组。
		  while(bis.read(b)!=-1){//输入流中的数据如果还有下一行(!=-1)将继续循环
			  bos.write(b);//将字节数组写入输出流。    
		  } 
		  }catch(Exception   e){     
			  System.out.println(e.toString());       
		  }finally{     
			  try{     
				  bos.flush();//刷新此缓冲的输出流。 
				  bis.close(); //关闭此输入流 。 
			  }catch(Exception   e){     
				  System.out.println(e.toString());       
			  }     
		  }  
	}

 

现在是基础工作都做完了,现在开发代码的开发,在微信开发文档中  http://mp.weixin.qq.com/wiki/17/c0f37d5704f0b64713d5d2c37b468d75.html 有提到每一个步骤,然后我们按照这个步骤开发:

 

第一步:用户同意授权,获取code

  这里的url就是前面所准备在properties中的url了。

 

/**
	 * 微信用户授权
	 * @Title: wechatOauth
	 * @param @param request
	 * @param @param response
	 * @param @param model
	 * @param @return
	 * @return String
	 * @throws xinz
	 */
	@RequestMapping("wechatOauth")
	public String wechatOauth(HttpServletRequest request,HttpServletResponse response,Model model)  {
		/**
		 *  1 第一步:用户同意授权,获取code
		 */
		//首先拿到微信公众号的AppID、AppSecret等参数
		String AppID = ZhtxHelper.getApplicationResourcesProp("sendSms","AppID");
		String urlOpen = ZhtxHelper.getApplicationResourcesProp("sendSms","url");
		//如果用户授权成功则跳转到此url
		String loginUrl = ""+urlOpen+"/zhtx-wap/weixin/getAccessToken";
		//用户授权,获取code
		String url = "https://open.weixin.qq.com/connect/oauth2/authorize?"
					+ "appid="+AppID+""
					+ "&redirect_uri="+loginUrl+""
					+ "&response_type=code"
					+ "&scope=snsapi_userinfo"
					+ "&state=123#wechat_redirect";
		//forward redirect
		return "redirect:"+url+""; 
	}

 

第二步:通过code换取网页授权access_token

 

/**
	 * 通过code换取网页授权access_token
	 * @Title: getAccessToken
	 * @param @param request
	 * @param @param response
	 * @param @param model
	 * @param @return
	 * @return String
	 * @throws xinz
	 */
	@RequestMapping("getAccessToken")
	public String getAccessToken(HttpServletRequest request,HttpServletResponse response,Model model) {
		//获取到返回的参数
		try {
			//首先拿到微信公众号的AppID、AppSecret等参数
			String AppID = ZhtxHelper.getApplicationResourcesProp("sendSms","AppID");
			String AppSecret = ZhtxHelper.getApplicationResourcesProp("sendSms","AppSecret");
			String code = request.getParameter("code");
			String url = null;
			if(code!=null){
				/**
				 *  2 第二步:通过code换取网页授权access_token
				 */
				//用户授权,获取code
				url = "https://api.weixin.qq.com/sns/oauth2/access_token?"
						+ "appid="+AppID+""
						+ "&secret="+AppSecret+""
						+ "&code="+code+""
						+ "&grant_type=authorization_code";
				String requestMethod = "GET";
				String outputStr = "";
				String httpRequest = WeixinUtil.httpRequest(url, requestMethod, outputStr);
				
				System.out.println("通过code换取网页授权access_token="+httpRequest);
				
				AccessTokenModel accTok = JSON.parseObject(httpRequest, AccessTokenModel.class);
				/**
				 *  4 第四步:拉取用户信息(需scope为 snsapi_userinfo)
				 */	                                                                      
				//用户授权,获取code
				String urlUser = "https://api.weixin.qq.com/sns/userinfo?"
						+ "access_token="+accTok.getAccess_token()+""
						+ "&openid="+accTok.getOpenid()+""
						+ "&lang=zh_CN";
				
				String httpUser = WeixinUtil.httpRequest(urlUser, requestMethod, outputStr);
				System.out.println("拉取用户信息=="+httpUser);
				
				WechatUser wechatUser = JSON.parseObject(httpUser, WechatUser.class);
				wechatUser.setAccess_token(accTok.getAccess_token());
				/**
				 *  5 附:检验授权凭证(access_token)是否有效
				 */
				WechatMsg checkAccessToken = checkAccessToken(wechatUser.getAccess_token(), wechatUser.getOpenid());
				if(checkAccessToken.getErrcode().equals("0")){
					CurrentSession.setAttribute("wechatUser", wechatUser);
					WechatUser wechatU = new WechatUser();
					wechatU.setOpenid(wechatUser.getOpenid());
					List<WechatUser> findWechatUser = wechatUserService.findWechatUser(wechatU);
					if(findWechatUser.size()>0){
						UserRegister userRegister = userService.findUserByOpenid(wechatUser.getOpenid());
						CurrentSession.setAttribute("user", userRegister);
						return "redirect:/user/userCenter";
					}else{
						
						return "/jsp/wechat/wechatregister"; 
					}
					
				}else{
					//如果access_token失效,则再次进行调用,并存储access_token值,access_token有效期为2个小时
					this.wechatOauth(request, response, model); 
				}
			}
		} catch (Exception e) {
			System.out.println("===拉取用户出错===");
			e.printStackTrace();
		}
		//forward redirect
		return "/jsp/wechat/wechatregister"; 
	}

 

第四步:拉取用户,和自己网站用户绑定

/**
	 * 微信关联用户
	 * @Title: saveWechatUser
	 * @param @param mobilePhone
	 * @param @param password
	 * @param @param validataCode
	 * @param @return
	 * @return String
	 * @throws xinz
	 */
	@RequestMapping("saveWechatUser")
	public String saveWechatUser(HttpServletResponse response,String mobilePhone,String password,String validataCode){
		//使用手机号来判断该手机是否在注册
		UserRegister userRegister = userService.findUserByPhone(mobilePhone);
		WechatUser wechatUser = (WechatUser)CurrentSession.getAttribute("wechatUser");
		WechatUser wechatU = new WechatUser();
		wechatU.setOpenid(wechatUser.getOpenid());
		List<WechatUser> findWechatUser = wechatUserService.findWechatUser(wechatU);
		if(findWechatUser.size()>0 && userRegister.getOpenid()!=null){
			CurrentSession.setAttribute("user", userRegister);
			return "redirect:/user/userCenter";
		}else{
			//如果没有注册,开始注册
			if(userRegister==null){
				Result<UserRegister> saveUserInfoApp = userRegisterService.saveUserInfoApp(mobilePhone, password, validataCode,wechatUser);
				if(saveUserInfoApp.getState()==1){
					//进行微信和用户的关联
					wechatUserService.saveWechatUser(wechatUser);
					CurrentSession.setAttribute("user", userRegister);
					return "redirect:/user/userCenter";
				}
			}else if(userRegister.getOpenid()==null || userRegister.getOpenid().equals("")){
			//否则,查询出用户信息,放入session中,关联微信,跳转到用户中心	
				UserRegister userReg = new UserRegister();
				userReg.setId(userRegister.getId());
				//存入微信openid
				userReg.setOpenid(wechatUser.getOpenid());
				userService.upUser(userReg);
				UserInfo user = new UserInfo();
				//存入微信头像
				//图片类型
				String dateStr =DateUtil.format(DateUtil.getCurrentDate(), "yyyyMMdd")  + "/";
				//图片类型
				String imgType = "JPG";
				//微信头像名称
				String app2DBarNameAndType = UuidUtil.getUUID()+"."+imgType;
				//微信头像路径
				String path =   ZhtxHelper.getApplicationResourcesProp("application","app.img.projectpath")+ SysConstant.GOODS2DBARPATH + dateStr;
				File file1 = new File(path);
				file1.mkdirs();
				//图片全路径
				String imgUrl = SysConstant.GOODS2DBARPATH + dateStr+app2DBarNameAndType;
				FileUtil.fileUpload(wechatUser.getHeadimgurl(), path);
				user.setRegisterId(userRegister.getId());
				user.setImageUrl(imgUrl);
				userInfoService.updateUserInfo(user);
				//存入微信用户
				wechatUserService.saveWechatUser(wechatUser);
				
				UserRegister userW = userService.findUserByPhone(mobilePhone);
				CurrentSession.setAttribute("user", userW);
				return "redirect:/user/userCenter";
			}else{
				CurrentSession.setAttribute("user", userRegister);
				return "redirect:/user/userCenter";
			}
		}
		return "redirect:/user/userCenter";
	}

 

附:检验授权凭证(access_token)是否有效

 

/**
	 * 检验授权凭证(access_token)是否有效
	 * @Title: checkAccessToken
	 * @param @param access_token 网页授权接口调用凭证,注意:此access_token与基础支持的access_token不同 
	 * @param @param openid 用户的唯一标识 
	 * @return WechatMsg   返回消息实体
	 * @throws xinz
	 */
	public static WechatMsg checkAccessToken(String access_token,String openid){
		 String requestMethod = "GET";
		 String outputStr = "";	
		 String url = "https://api.weixin.qq.com/sns/auth?"
		 		+ "access_token="+access_token+""
		 		+ "&openid="+openid+"";
		 String httpmsg = WeixinUtil.httpRequest(url, requestMethod, outputStr);
		 System.out.println("拉取用户信息返回消息=="+httpmsg);
			
		 WechatMsg msg = JSON.parseObject(httpmsg, WechatMsg.class);
	    
		 return msg;
	}

 然后在网页端,则是需要编写H5页面,进行自己网站和微信用户的关联,我这里是使用手机号,用户输入手机号,进行判断,如果注册过就直接关联,如果用户没有注册则进行注册后关联,完成后跳转到会员中心。

 

 

 

 



已有 0 人发表留言,猛击->> 这里<<-参与讨论


ITeye推荐



相关 [微信 开发 oauth2.0] 推荐:

微信开发之获取OAuth2.0网页授权认证和获取用户信息进行关联

- - ITeye博客
        最近有做了关于微信公众号和自己网站用户进行用户关联授权登录的一个功能,主要是用户关注该公众号,点击会员中心,则会弹出需要关联授权的网页授权:OAuth2.0网页授权,然后用户同意获取用户信息,进行用户和网站的关联,然后用户则可以使用微信进行登录.         本次做的是一个在Java的Action层处理各个返回参数获取数据.

微信开发入门

- - 行业应用 - ITeye博客
【做微信平台开发需要以下步骤,wx.zip示例可以参考,修改配置即可】. 1.申请一个公众号(订阅号或者服务号). 2.需要有自己的服务器(建议使用花生壳做内网映射). * 检查是否是微信发送的请求. * @param signature 签名. * @param timestamp 时间戳. * @param nonce 随机数.

微信公众平台开发(一)

- - BlogJava-首页技术区
  开始微信公众平台的开发,我们首先要了解微信平台可以帮助我们做哪些事情. 使用您的公众账号登陆http://mp.weixin.qq.com/,选择菜单--高级功能-开发模式--查看文档,即能看到微信公众平台目前所能开发的功能. 接受用户发送给您公众账号的消息. 需要特别说明的是,发送消息和回复消失是一个连贯的过程,只能在一个对话中完成.

如何成为微信开发者

- - 神刀网
要成为微信开发者,准备工作如下:. a.这个可以自己购买,如果之前已有网站,可直接使用其服务器,这样也不用再购买域名了. b.也可以使用免费的服务器,搜索一下,有很多. c.还可以使用 百度云开发平台或者 新浪云平台,是免费的. a.如果服务器自己购买,也需要购买域名,然后要设置域名DNS,将域名绑定到购买的服务器.

微信公众平台接口开发

- - CSDN博客互联网推荐文章
随着微信公众平台的开放,微信营销推广也越发受到重视. 现在企业越来越注重求职者是否拥有“微信公众平台接口开发”的经验. 现在参考资料介绍下微信公众平台接口开发模式:. 首先你得有个微信公众平台账号,注册地址:http://mp.weixin.qq.com/. 开发者提交信息后,微信服务器将发送GET请求到填写的URL上,GET请求携带四个参数:.

微信公众平台开发入门

- - Web前端 - ITeye博客
在这篇微信公众平台开发教程中,我们假定你已经有了PHP语言程序、MySQL数据库、计算机网络通讯、及HTTP/XML/CSS/JS等基础. 我们将使用微信公众账号方倍工作室作为讲解的例子,二维码见底部. 本系列教程将引导你完成如下任务:. 我们使用SAE新浪云计算平台作为服务器资源,并且申请PHP环境+MySQL数据库作为程序运行环境.

Vue2 全家桶与微信开发

- - IT瘾-dev
此项目本身有一个APP了,为了方便将APP和微信端数据打通,需要用户微信和APP用户绑定. 在开发的过程中单页面的模式在微信JS API的配置踩了很多坑,特别是IOS. 由于本人表述能力和篇幅有限Orz,这里只介绍关键的实现步骤和代码,有些安全的地方和路由地方处理当时比较暴力没有细化,还望交流指导.

如何基于微信开放接口开发企业的微信 CRM?

- - 极客公园-GeekPark
我是极客公园黑板报认证值日生. [核心提示]企业要开发微信 CRM,首先要从业务架构上进行设计清楚. 微信 CRM 的本质,是在微信渠道上利用微信的特点和接口而扩展的 CRM 系统. 业内一直都在传说 微信是天生的 CRM,可是没有人看到过微信 CRM 的真容. 随着微信最新公众平台的改版和开放接口的微信认证开放,微信 CRM 离企业越来越近.

微信公众平台开发(三)--位置信息的识别

- - BlogJava-首页技术区
位置识别这是实际应用经常应用的消息,特别是很多商家,通过了解用户位置,给用户提供特别的产品或是商场的推荐. 其中用户可能发送两种类型的消息:. 2.路名、标志性建筑或是商场名称. 认识一下,微信地理位置消息,包含一些什么信息. <Label><![CDATA[位置信息]]></Label>.

摩拜单车微信小程序开发技术总结

- - SegmentFault 最新的文章
摩拜单车小程序已于微信小程序上线第一天正式发布,刷爆微博媒体朋友圈. 本文主要讲讲技术方向的总结,在段时间的开发周期内内如何一步步从学习到进阶. 微信小程序没有HTML的常用标签,而是类似. React的微信自定义组件,比如. window变量,但微信提供了. React的state)来改变视图展现.