微信开发——授权

 

注意:先大致浏览全文,如果还行再仔细看   代码下载链接放到最后了 用的servlet实现的 文章中用的springmvc如果对spring不熟悉,看代码就好了。代码配置文件可以使用来优化,工具类写好没用

 

不管是不是开发者账号,都可以在测试号中拿到所有的开发权限,这样就可以进行相关的操作了。所以接下来的总结都是在测试号中进行的。

首先微信绑定是要设置服务器接口配置,回调域名的以及确认页面,这样才能拿到openid以及相对详尽的信息。

1.准备工作:

(1).设置服务器接口配置

如图:

202945_4TyX_2918544.png

servlet 

WechatValidate在java中是一个servlet,然后微信服务器会向这一个servlet发一个get请求(如果配置文本消息也会向这一个servlet发送post(xml格式)请求),具体的验证代码:

@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {
		
		String signature = req.getParameter("signature");
		String timestamp = req.getParameter("timestamp");
		/***/
		System.out.println("=================================");
		System.out.println(timestamp);
		String nonce = req.getParameter("nonce");
		String echostr = req.getParameter("echostr");
		String token = "viakiba";//这里是和配置里面一致
		
		//验证配置
		String signCompar = Sha1.getSHA1(token, timestamp, nonce);
		
		PrintWriter pw = resp.getWriter();
		
		if(signCompar.equals(signature)){
			pw.print(echostr);
		}
	}
Sha1文件如下
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
public class Sha1 {
	
	public static String getSHA1(String token, String timestamp, String nonce)  {
        String[] array = new String[] { token, timestamp, nonce };
        StringBuffer sb = new StringBuffer();
        // 字符串排序
        Arrays.sort(array);
        for (int i = 0; i < 3; i++) {
            sb.append(array[i]);
        }
        String str = sb.toString();
        // SHA1签名生成
        try {
			MessageDigest md = MessageDigest.getInstance("SHA-1");
			md.update(str.getBytes());
			byte[] digest = md.digest();
			StringBuffer hexstr = new StringBuffer();
			String shaHex = "";
			for (int i = 0; i < digest.length; i++) {
			    shaHex = Integer.toHexString(digest[i] & 0xFF);
			    if (shaHex.length() < 2) {
			        hexstr.append(0);
			    }
			    hexstr.append(shaHex);
			}
			System.out.println(hexstr);
			return hexstr.toString();
		} catch (NoSuchAlgorithmException e) {
			return null;
		}
}
	
}
注意web.xml中配置servlet路径
<servlet>
  	<servlet-name>vk</servlet-name>
  	<servlet-class>haust.viakiba.servlet.Vk</servlet-class>
  </servlet>
  <servlet-mapping>
  	<servlet-name>vk</servlet-name>
  	<url-pattern>/WechatValidate</url-pattern>
  </servlet-mapping>

(2)配置回调域名:

203108_Od8q_2918544.png

 注意:

不必为这种一级域名,比如wechat.viakiba.cn也是可以的,那个redirecturi要在这个域名下面,如(  我的链接是 http://viakiba.cn/auth/entranceUser.action,那么上面就写 viakiba 。如果是: http://wechat.viakiba.cn/auth/entranceUser.action   那么可以写 wechat.viakiba.cn ,也可以写 viakiba.cn),只要域名可以指向项目的部署的服务器就行。这里,80端口可以访问tomcat的项目。具体的tomcat配置如下:

server.xml 文件:

<?xml version='1.0' encoding='utf-8'?>
<Server port="8005" shutdown="SHUTDOWN">
  <Listener className="org.apache.catalina.startup.VersionLoggerListener" />
  
  <!--APR library loader. Documentation at /docs/apr.html -->
  <Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" />
  <!--Initialize Jasper prior to webapps are loaded. Documentation at /docs/jasper-howto.html -->
  <Listener className="org.apache.catalina.core.JasperListener" />
  <!-- Prevent memory leaks due to use of particular java/javax APIs-->
  <Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" />
  <Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />
  <Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener" />
  <!-- Global JNDI resources
       Documentation at /docs/jndi-resources-howto.html
  -->
  <GlobalNamingResources>
    <Resource name="UserDatabase" auth="Container"
              type="org.apache.catalina.UserDatabase"
              description="User database that can be updated and saved"
              factory="org.apache.catalina.users.MemoryUserDatabaseFactory"
              pathname="conf/tomcat-users.xml" />
  </GlobalNamingResources>
  <Service name="Catalina">
    <!--useBodyEncodingForURI="true" URIEncoding="UTF-8"    地址栏传中文  这里配置80端口-->
    <Connector port="80" protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="8443" useBodyEncodingForURI="true" URIEncoding="UTF-8"/>
    
    <Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />
    <Engine name="Catalina" defaultHost="viakiba">
      <Realm className="org.apache.catalina.realm.LockOutRealm">
        
        <Realm className="org.apache.catalina.realm.UserDatabaseRealm"
               resourceName="UserDatabase"/>
      </Realm>
      <!-- 这里配置域名,这样通过域名就可以访问项目了 -->
      <Host name="viakiba.cn"  appBase="webapps"
            unpackWARs="true" autoDeploy="true"> 
            <!-- 这里配置默认项目,配置后,无论域名后跟不跟项目名都可以访问 -->
			<Context path="" docBase="/wechatvk" debug="0" reloadable="true"></Context>	
            <!-- 这里配置虚拟目录,一般图片存储需求不大,不需要图片服务器的这么做,而不是放到webroot 下面,要不然每次部署都要移动目录 -->
			<Context path="/image" docBase="D:/images"  reloadable="true"></Context> 
      </Host>
	  <Host name="www.viakiba.cn"  appBase="webapps"
            unpackWARs="true" autoDeploy="true"> 
			<Context path="" docBase="/wechatvk"  reloadable="true"></Context> 
			<Context path="/image" docBase="D:/images"  reloadable="true"></Context> 
      </Host>
    </Engine>
  </Service>
</Server>

微信开发,内网穿透工具:

ngrock

2.取openid

文档:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140842&token=&lang=zh_CN

urlencoding: http://tool.chinaz.com/tools/urlencode.aspx

(1)scope=snsapi_base(仅拿到openid)

获取code:

首先要知道微信公众号的appid和appsecret

测试号的如下:

203225_2Vcr_2918544.png

 

首先要让用户点击一个实现拼接好的链接,这样才能拿到code参数

这个链接特点如下:

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

           1.appid=APPID: 把APPID更换成测试号的。我的如下:wx32f1fdf5edf36bfb

           2.redirect_uri=REDIRECT_URI:把需要跳转到的链接写上,我在java web中使用了springmvc框架,所以我的路径如下:http://viakiba.cn/auth/entranceUser.action  (web.xml配置拦截.action后缀的请求)

如图(也可以使用servlet):

203243_2IjN_2918544.png

 

http://viakiba.cn/auth/entranceUser.action 链接进行urlEncoding编码:编码工具(urlencoding: http://tool.chinaz.com/tools/urlencode.aspx

我的结果如下:

http%3a%2f%2fviakiba.cn%2fauth%2fentranceUser.action

        3.scope=SCOPE:这里使用snsapi_base去替换即scope=snsapi_base。这样,将看不到授权页面,静默跳转。

授权页面 例子如下:

203310_LIFo_2918544.png

此时拼接好的链接,整体如下:

https://open.weixin.qq.com/connect/oauth2/authorize?appid=wx32f1fdf5edf36bfb&redirect_uri=http%3a%2f%2fviakiba.cn%2fauth%2fentranceUser.action&response_type=code&scope=snsapi_base&state=STATE#wechat_redirect

未修改的参数默认即可   参数顺序必须如此,不可调换顺序

 这是请求会带着code参数重定向到刚才配置的链接的(http://viakiba.cn/auth/entranceUser.action )方法中,这是同果request的getParameter方法是可以拿到的(和取地址栏参数的方式一致)。我使用的springmvc,自动封装到参数中:

203347_aA01_2918544.png

方法代码如下:

@RequestMapping("/entranceUser")
	public String authUser(String code,HttpServletRequest request){
		//  https://api.weixin.qq.com/sns/oauth2/access_token?appid=wx32f1fdf5edf36bfb&secret=00331d6bac9330b7d7020fa8eb6e4721&code=CODE&grant_type=authorization_code
		String wcopenid = Validate.getUserInfoAccessToken(code);
		request.getSession().setAttribute("wcopenid",wcopenid);
		System.out.println("code##########va"+code);
		System.out.println("openid********va"+wcopenid);
		User user=userServiceImpl.getUserByOpenid(wcopenid);
		if(user==null){
			return "querykey";
		}
		request.getSession().setAttribute("user",user);
		return "redirect:/user/getUserOrderList.action";
	}

Validate.getUserInfoAccessToken()方法是取openid的方法:

public static String getUserInfoAccessToken(String code) {
		String access_token_uri = "https://api.weixin.qq.com/sns/oauth2/access_token?appid="+appid+"&secret="+secret+"&code="+code+"&grant_type=authorization_code";
        String openid = WcUtils.loadJson(access_token_uri);
        /*
         { "access_token":"ACCESS_TOKEN",    
		 "expires_in":7200,    
		 "refresh_token":"REFRESH_TOKEN",    
		 "openid":"OPENID",    
		 "scope":"SCOPE" } 
         */
        Openid parse = JSON.parseObject(openid,Openid.class);
        //拿到id
        openid = parse.getOpenid();
        return openid;
    }

url的解释:

https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code

appid=APPID:wx32f1fdf5edf36bfb 

secret=SECRET:00331d6bac9330b7d7020fa8eb6e4721

不懂看上面的截图

code=CODE:上一步请求时拿到的code

然后loadjson是一个工具类,这里使用的时发送get请求,还有一个post请求:

package com.xdailiao.utils.wcutil;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
public class WcUtils {
	//返回json字符串  get
	public static String loadJson (String url) {  
		 StringBuilder json = new StringBuilder();  //stringbuffer更好
		 try {  
			 System.out.println("进入get请求。。。。。。accessToken");
		     URL urlObject = new URL(url);  
		     URLConnection uc = urlObject.openConnection();  
		     BufferedReader in = new BufferedReader(new InputStreamReader(uc.getInputStream(),"utf-8"));  
		     String inputLine = null;  
		     while ( (inputLine = in.readLine()) != null) {  
		           json.append(inputLine);  
		     	}  
		     in.close();  
		     } catch (Exception e) {  
		       e.printStackTrace();  
		     	}  
		     return json.toString();  
	 }
		
	//返回json字符串  post
	public static String loadJson(String strURL,String params){
		System.out.println(strURL);  
        System.out.println(params);  
        try {  
            URL url = new URL(strURL);// 创建连接  
            HttpURLConnection connection = (HttpURLConnection) url  
                    .openConnection();  
            connection.setDoOutput(true);  
            connection.setDoInput(true);  
            connection.setUseCaches(false);  
            connection.setInstanceFollowRedirects(true);  
            connection.setRequestMethod("POST"); // 设置请求方式  
            connection.setRequestProperty("Accept", "application/json"); // 设置接收数据的格式  
            connection.setRequestProperty("Content-Type", "application/json"); // 设置发送数据的格式  
            connection.connect();  
            OutputStreamWriter out = new OutputStreamWriter(  
                    connection.getOutputStream(), "UTF-8"); // utf-8编码  
            out.append(params);  
            out.flush();  
            out.close();  
            // 读取响应  
            int length = (int) connection.getContentLength();// 获取长度  
            InputStream is = connection.getInputStream();  
            if (length != -1) {  
                byte[] data = new byte[length];  
                byte[] temp = new byte[512];  
                int readLen = 0;  
                int destPos = 0;  
                while ((readLen = is.read(temp)) > 0) {  
                    System.arraycopy(temp, 0, data, destPos, readLen);  
                    destPos += readLen;  
                }  
                String result = new String(data, "UTF-8"); // utf-8编码  
                System.out.println(result);  
                return result;  
            }  
        } catch (IOException e) {  
            // TODO Auto-generated catch block  
            e.printStackTrace();  
        }  
        return "error"; // 自定义错误信息  
	}
}

其实,这里拿到的json字符串,可以使用fastjson工具包中的JSON.praseObject(json,Map.class);转为map,通过access_token得到ACCESS_TOKEN,通过openid得到openid。我这里封装的对象。

具体的json转换请百度。

这是拿到accesstoken其实可以接着拿到接下来的用户的信息的比如头像,昵称一类的。这和snsapi_userinfo唯一的区别,没有授权这一步,也就是用户无感知。但是拿到的信息是可以一致的。

此时id就拿到了,用户对于一个公众号来是不变的。所以,简单的绑定,进展到这就行了。不必往下做了。

测试号仅对于此表中的用户有效:

203532_sd7j_2918544.png

snsapi_base(包括openid,用户头像,地区,昵称等信息)

那么接下来使用

snsapi_base模式拿到用户信息,因为上面已经再拿到openid的时候拿到了access_token一级refresh_token所以接下来使用access_token,以及openid拿到用户信息

/**
	 * 拿到用户详细信息
	 * @param code
	 * @return
	 */
	public static String getUserinfo(String access_token,String openid) {
		String json = UrlReq.loadJson("https://api.weixin.qq.com/sns/userinfo?access_token="+access_token+"&openid="+openid+"&lang=zh_CN ");
		
		return json;
	}

其他:

refresh 我的理解是可以服务器在一定时间内,可以刷新拿到用户的微信信息做到与微信信息的同步(30天)

上述代码:

请到:http://download.csdn.net/detail/meryhuang/9688127 

或者联系:QQ:892645423

(2)scope=snsapi_userinfo

代码同 scope=snsapi_base 配置也和上面一致。只需吧引导链接scope=snsapi_userinfo即可。这是点击链接会先进入确认登陆页面。

 

转载于:https://my.oschina.net/viakiba/blog/791122

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值