微信公众号开发入门demo,获取toekn,用户个人信息等

微信公众号API详解

1.微信公众号测试平台

http://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=sandbox/login

扫描进入后可以获得appid和appsecret

并且需要配置自己的域名

2.工具类,java发送HTTP请求的

package com.test.util;

import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.net.URLConnection;


public class Util {
	private static final String DEF_CHARSET="UTF-8";
	
	/**
	 * 向指定的地址发送get请求
     * 如果地址中有中文可能会造成乱码,可以用URLEncoder.encode("中文", "UTF-8")处理
	 * @param url
	 * @return
	 */
	public static String get(String url) {
		StringBuilder sBuilder = new StringBuilder();
		try {
			URL urlObj = new URL(url);
			//开链接
			URLConnection connection = urlObj.openConnection();
			InputStream is = connection.getInputStream();
			byte[] b = new byte[1024];
			int len;
			
			while ((len=is.read(b))!=-1 ) {
				sBuilder.append(new String(b,0,len)); 
			}
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} 
		
		return sBuilder.toString();
	}
	/**
	 * 向指定地址发送post请求,带着数据  
	 * data格式"qrcode=1111&longitude=21.222&latitude=23.344&address=空间大姐夫"
	 * @param url
	 * @param data
	 * @return
	 */
	public static String post(String url,String data) {
		StringBuilder sBuilder = new StringBuilder();
		try {
			URL urlObj = new URL(url);
			//开链接
			URLConnection connection = urlObj.openConnection();
			connection.setRequestProperty("charset", "utf-8");
			
			//要发送数据出去,必须要设置为可发送数据状态
			connection.setDoOutput(true);
			//获取输出流
			OutputStream os = connection.getOutputStream();
			//写出数据
			os.write(data.getBytes());
			os.close();
			//获取输入流读取数据
			InputStream is = connection.getInputStream();
			byte[] b = new byte[1024];
			int len;
			
			while ((len=is.read(b))!=-1 ) {
				sBuilder.append(new String(b,0,len)); 
			}
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		return sBuilder.toString();
	}
	public static void main(String[] args) {
		
		post("http://192.168.1.4:8080/zzserver/qrcodejb/saveQRCodeJB","qrcode=1111&longitude=21.222&latitude=23.344&address=空间大姐夫");

	}
}

3.写一个servlet

package com.test.servlet;

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.test.service.WxService;

import net.sf.json.JSONObject;


/**
 * Servlet implementation class TestServlet
 */
@WebServlet("/TestServlet")
public class TestServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;
       
    /**
     * @see HttpServlet#HttpServlet()
     */
    public TestServlet() {
        super();
        // TODO Auto-generated constructor stub
    }

	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		String code = request.getParameter("code");
		String result=WxService.getOpenId(code);
		//String token = JSONObject.fromObject(result).getString("access_token");此种方法获取的token会报错!!!!!!!!!!!
		String token =WxService.getAccessToken();
		String openid = JSONObject.fromObject(result).getString("openid");
		System.out.println("doget======token:"+token);
		System.out.println("doget======openid:"+openid);
		String userInfo=WxService.getUserInfo(token,openid);
		System.out.println(userInfo);
	}

	/**
	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
		doGet(request, response);
	}

}

4.写一个service

package com.test.service;

import java.io.InputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import com.test.model.AccessToken;
import com.test.util.*;

import jdk.nashorn.api.scripting.URLReader;
import net.sf.json.JSONObject;


public class WxService {
	private static final String APPID="你自己公众号的appid";
	private static final String APPSECRET="你自己公众号的APPSECRET";
	private static final String GET_TOKEN_URL="https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET";
	//用于存储token
	private static AccessToken at;
	/**
	 * 获取token
	 */
	private static void getToken() {
		String url = GET_TOKEN_URL.replace("APPID", APPID).replace("APPSECRET", APPSECRET);
		System.out.println(url);
		String str = Util.get(url);
		
		
		
		JSONObject object= JSONObject.fromObject(str);
		String token = object.getString("access_token");
		String expireIn = object.getString("expires_in");
		//创建token对象并存起来
		at = new AccessToken(token,expireIn);
		
		
	}
	/**
	 * 向外暴露获取token的方法
	 * @return
	 */
	public static String getAccessToken() {
		if(at==null || at.isExpired()) {
			System.out.println("1");
			
			getToken();
		}
		return at.getAccessToken();
	}
	/**
	 * 获取用户的基本信息
	 * @param openId
	 * @return
	 */
	public static String getUserInfo(String accessToken,String openId) {
		String url="https://api.weixin.qq.com/cgi-bin/user/info?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN";
		url = url.replace("ACCESS_TOKEN", accessToken).replace("OPENID", openId);
		String result=Util.get(url);
		System.out.println("getUserInfo:"+result);
		return  result;
	}
	/**
	 * 根据code获取openId
	 * 注意:此方法只能获取openid,accesstoken要用getAccessToken()获取,否则报错;
	 * @param code
	 * @return
	 * {"access_token":"17_GGijMMF0rx8PpOrQ7QaHXzXvWa5TuaHl4TJ_uTrL0t4SJNy9KdX2OqUytRmMnFto919ikZEH_pwNolsolZUJ49PaEMSP1lXc80VKa53r0fo","expires_in":7200,"refresh_token":"17_MhG27a3Y84FJEAms_8P-LQx1sfCRwlRy5DFG3zHJ28XuSqLr94GgSd8H9fZVx7Cz8eoy5nMuO0RfflJHcOi7K3Izvf-z2nBhFB2dlScfqgo","openid":"opPyS0gqyIf5bDT0hpyahIAOl5iU","scope":"snsapi_userinfo"}
	 */
	public static String getOpenId(String code) {
		String url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code";
		url=url.replace("APPID", APPID).replace("SECRET", APPSECRET).replace("CODE", code);
		String result = Util.get(url);
		System.out.println("getOpenId:"+result);
		return result;
	}
	public static void main(String[] args) {
		//getAccessToken();
		//getUserInfo("");
	}
	
	
	
	
	/**
	 * 验证签名
	 */
	public static boolean check(String token, String timestamp, String nonce, String signature) {
		/**
		 * 1)将token、timestamp、nonce三个参数进行字典序排序 
		 * 2)将三个参数字符串拼接成一个字符串进行sha1加密 
		 * 3)开发者获得加密后的字符串可与signature对比,标识该请求来源于微信
		 */
		String[] strs=new String[] {token,timestamp,nonce};
		System.out.println(strs);
		Arrays.sort(strs);
		System.out.println(strs);
		String str = strs[0]+strs[1]+strs[2];
		String mysig=sha1(str);
		System.out.println(mysig);
		System.out.println(signature);
		
		return mysig.equalsIgnoreCase(signature);
	}
	
	private static String sha1(String str) {
		//获取一个加密对象
		try {
			MessageDigest md = MessageDigest.getInstance("sha1");
			//加密
			byte[] digest = md.digest(str.getBytes());
			char[] chars = {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
			StringBuilder sb = new StringBuilder();
			//处理加密结果
			for(byte b:digest) {
				sb.append(chars[(b>>4)&15]);
				sb.append(chars[b&15]);
				
			}
			return sb.toString();
			
		} catch (NoSuchAlgorithmException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return null;
	}

	public static Map<String, String> parseRequest(HttpServletRequest request) {
		Map<String,String> map = new HashMap<String,String>();
		try {
			InputStream is=request.getInputStream();
			SAXReader reader = new SAXReader();
			//读取输入流
			Document document = reader.read(is);
			//根据文档对象获取节点
			Element root = document.getRootElement();
			//获取根节点的所有子节点
			List<Element> elements = root.elements();
			for (Element e : elements) {
				map.put(e.getName(), e.getStringValue());
			}
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return map;
	}

}

5.用来存放token的实体类

package com.test.model;

public class AccessToken {
	private String accessToken;
	private long expireTime;
	public String getAccessToken() {
		return accessToken;
	}
	public void setAccessToken(String accessToken) {
		this.accessToken = accessToken;
	}
	public long getExpireTime() {
		return expireTime;
	}
	public void setExpireTime(long expireTime) {
		this.expireTime = expireTime;
	}
	public AccessToken(String accessToken, String expireIn) {
		super();
		this.accessToken = accessToken;
		
		this.expireTime = System.currentTimeMillis()+Integer.parseInt(expireIn)*1000;
	}
	/**
	 * 查看是否国企
	 * @return
	 */
	public boolean isExpired() {
		return System.currentTimeMillis()>expireTime;
	}
}

 

项目源码以及jar等在github上,地址为 https://github.com/441985745/studyWechat

<think>首先,用户的问题是:"我想在TP8多应用模式下,如何在接口中获取中间件解析后的token中的uid 请问TP8 多应用模式 获取中间件解析的token uid request->param"。这看起来是关于ThinkPHP 8框架(TP8)的,用户想知道如何在多应用模式下,从接口中获取中间件解析后的token中的uid。 关键点: - TP8:ThinkPHP 8框架。 - 多应用模式:在ThinkPHP中,多应用模式允许一个框架运行多个独立的应用。 - 获取中间件解析的token:用户使用了中间件来解析token,比如JWT或类似的身份验证机制。 - 获取uid:用户ID,通常存储在token中。 - request->param:可能指的是通过请求对象获取参数,但用户可能想表达如何从请求中获取解析后的数据。 在ThinkPHP中,中间件通常用于处理请求前后,比如身份验证中间件会解析token并将用户信息存储在请求对象中。所以,获取解析后的uid应该通过请求对象。 步骤: 1. **中间件设置**:在中间件中,解析token后,将uid或其他用户信息附加到请求对象上。例如,在ThinkPHP中,可以使用`$request->user = $user;`或类似方式。 2. **在控制器中获取**:在控制器方法中,通过依赖注入或直接访问请求对象来获取uid。 用户提到了"request->param",这可能是误导,因为`param`通常用于获取查询参数或表单数据,而不是中间件设置的数据。正确的方式是使用请求对象上的自定义属性。 在ThinkPHP 8中,推荐使用依赖注入来获取请求对象。 例如: - 在中间件中: ```php public function handle($request, \Closure $next) { $token = $request->header('Authorization'); // 或其他方式获取token $user = $this->parseToken($token); // 解析token,获取用户信息 $request->user = $user; // 将用户信息附加到请求对象 return $next($request); } ``` - 在控制器中: ```php public function someMethod(Request $request) { $uid = $request->user->uid; // 或类似方式 // 使用$uid } ``` 用户指定了"多应用模式",但在多应用模式下,中间件和控制器的工作原理基本相同,因为每个应用有自己的路由和中间件堆栈。所以,方法应该类似。 现在,关于系统级指令: - 所有行内数学表达式使用$...$格式:但这个问题不涉及数学,所以可能不需要数学表达式。 - 独立公式使用$$...$$:同样,不适用。 - LaTeX语法正确:如果使用数学,但这里不需要。 - 使用中文回答:整个回答必须用中文。 - 生成相关问题:在最后,添加相关问题部分。 - 引用标识:如果引用内容,添加[^1]等,但用户没有提供引用,所以可能不需要,除非我引用通用知识。 用户提供的示例是关于快速排序的,但用户问题完全不同,所以我应该忽略示例内容,专注于回答。 回答结构: - 清晰、逐步解决问题。 - 保证真实可靠:基于ThinkPHP 8的文档和最佳实践。 大纲回答: 1. **解释上下文**:简要说明在ThinkPHP 8多应用模式下如何设置中间件来解析token。 2. **步骤**: - 如何定义中间件。 - 在中间件中解析token并附加到请求对象。 - 在控制器中获取uid。 3. **代码示例**:提供代码片段来演示。 4. **注意事项**:提到多应用模式下的差异(如果有)。 5. **相关问题**:生成几个相关问题。 相关问题示例: - 如何在ThinkPHP 8中配置JWT中间件? - 多应用模式下如何共享中间件? - 如何测试token解析功能? 确保回答用中文。 最终输出: - 回答部分。 - §§相关问题§§部分。</think>### ThinkPHP 8 多应用模式下获取中间件解析的 token 中的 uid 在 ThinkPHP 8 的多应用模式下,获取中间件解析后的 token 中的 `uid`(用户 ID)是一个常见需求。通常,这涉及身份验证中间件(如 JWT 或自定义 token 解析器)将解析后的用户信息附加到请求对象上。以下是详细步骤和代码示例,确保操作可靠且符合框架最佳实践。 #### 步骤 1: 设置中间件解析 token 在中间件中解析 token 后,将用户信息(包括 `uid`)附加到请求对象(`Request`)上。以下是标准做法: - **创建中间件**:在应用目录下创建中间件文件(如 `app/middleware/AuthMiddleware.php`)。 - **解析 token**:在中间件的 `handle` 方法中,从请求头或参数获取 token,解析后提取 `uid`。 - **附加到请求对象**:使用 `$request->user` 或自定义属性存储解析结果。 ```php <?php namespace app\middleware; use think\Request; class AuthMiddleware { public function handle(Request $request, \Closure $next) { // 从请求头获取 token(例如:Authorization: Bearer xxx) $token = $request->header('Authorization'); $token = str_replace('Bearer ', '', $token); // 清理 token 格式 // 解析 token 并获取 uid(示例使用 JWT,实际替换为您的解析逻辑) $uid = $this->parseToken($token); // 假设 parseToken 返回 uid // 将 uid 附加到请求对象,便于后续访问 $request->uid = $uid; // 直接附加为属性 // 或使用更结构化的方式:$request->user = ['uid' => $uid]; return $next($request); } private function parseToken($token) { // 实际解析逻辑(示例:伪代码) // 例如使用 JWT:\Firebase\JWT\JWT::decode($token, $key, ['HS256']); return 123; // 返回解析后的 uid } } ``` #### 步骤 2: 注册中间件 在多应用模式下,每个应用独立配置中间件。在应用的路由或全局中间件配置中注册: - **全局中间件**:在 `app/middleware.php` 文件中注册,适用于所有路由。 - **路由中间件**:在路由定义中指定,更灵活。 ```php // 文件:app/middleware.php(全局注册) return [ // 其他中间件... \app\middleware\AuthMiddleware::class, ]; ``` ```php // 或在路由中注册(文件:app/route/app.php) use think\facade\Route; use app\middleware\AuthMiddleware; Route::group(function () { Route::get('user/profile', 'User/profile'); })->middleware(AuthMiddleware::class); // 仅对该路由组生效 ``` #### 步骤 3: 在控制器中获取 uid 在控制器方法中,通过依赖注入获取 `Request` 对象,直接访问中间件附加的 `uid` 属性。**不要使用 `request->param()`**,因为它仅用于获取请求参数(如 GET/POST 数据),而非中间件解析的数据。 ```php <?php namespace app\controller; use think\Request; class User { public function profile(Request $request) { // 直接访问中间件附加的 uid $uid = $request->uid; // 如果附加为 $request->uid // 或:$uid = $request->user['uid']; // 如果附加为数组 // 示例:返回 uid return json(['uid' => $uid]); } } ``` #### 关键注意事项 - **多应用模式差异**:在多应用模式下,每个应用有独立的中间件配置。确保中间件在正确的应用目录(如 `app/app_name/middleware/`)中创建和注册。 - **token 解析库**:实际项目中,使用成熟的库(如 `firebase/php-jwt`)解析 token。安装后集成到中间件。 - **错误处理**:在中间件中添加 token 无效时的异常处理(如返回 401 响应)。 - **性能**:避免重复解析 token,确保中间件只运行一次[^1]。 - **`request->param` 误解**:`$request->param()` 用于获取请求参数(如 `?id=123`),**不能用于获取中间件数据**。必须通过请求对象的自定义属性访问。 通过以上步骤,您可以在任何接口控制器中安全获取解析后的 `uid`。测试时,确保 token 正确传递(如 Postman 的 Authorization 头)。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值