首先,openid是什么?
openid是一个微信号与一个公众号对应一个固定不变的openid。所以一个微信号在一个公众号下的openid是不变的,如果换了一个对应的公众号,那就是另一个openid了。openid只有在微信自带浏览器中打开的项目才可获取到。
准备:
1、首先你要有一个公众号,还有一个外网可访问的域名。因为只有企业号才有获取用户信息的接口权限,所以这里就以企业号为例。
2、获取openid需要的公众号的 appid 和 secret:登陆公众平台查看开发----->基本配置中的开发者ID(AppID)和 开发者密码(AppSecret)就是。

3、设置网页授权域名:登陆公众平台 开发----->接口权限------>网页服务----->网页授权域名),这里需要注意,设置授权域名的时候需要先下载一个认证文件,你把这个认证文件放到你部署的服务器web项目的根目录底下,比如springboot项目通常放到static目录下,而且你的项目能够被外网访问到才行,然后点击保存,如果微信服务器能访问到这个文件,就会提示保存成功。你添加的这个域名就是你获取openid的web项目发布的域名,这里注意服务器请一定跑在80端口。

操作流程:
上面的准备工作完毕之后,接下来就可以开始正式进入获取用户openid的流程之中了。
获取工作大致分为两步:
1.通过调用https://open.weixin.qq.com/connect/oauth2/authorize接口获取到code
请求方法:
https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect
参数说明:

:在线urlencode地址:http://www.jsons.cn/urlencode/
2.得到code作为一个参数调用https://api.weixin.qq.com/sns/oauth2/access_token接口获取到openid。
请求方法:
获取code后,请求以下链接获取access_token: https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code
参数说明:

下面我们逐步的进行说明:
1、其实第一步可以用两种方式实现:
一种是在公众号中配置链接,比如在自动回复中设置a标签链接,或者新建菜单链接等,然后在用户点击你的链接时,你就能在你的controller中通过HttpServletRequest 获得对应的code值,然后你就可以根据code值进行第二步操作。

controller中的代码如下:
@RequestMapping("/login")
public String loginDemo(HttpServletRequest request, HttpServletResponse response) {
System.out.println("+++++++微信+++++++"+request.getParameter("code"));
}
另一种方式是用户通过链接登录都你的项目时你主动发送请求获取对应的code,其代码如下:
1. public class WxCodeServlet extends HttpServlet {
3. public void doGet(HttpServletRequest request, HttpServletResponse response)
4. throws ServletException, IOException {
6. doPost(request, response);
7. }
9. public void doPost(HttpServletRequest request, HttpServletResponse response)
10. throws ServletException, IOException {
12. response.setContentType("text/html");
13. response.setCharacterEncoding("UTF-8");
14. request.setCharacterEncoding("UTF-8");
15. //这里要将你的授权回调地址处理一下,否则微信识别不了
16. String redirect_uri=URLEncoder.encode("/*你的授权回调地址*/", "UTF-8");
17. //简单获取openid的话参数response_type与scope与state参数固定写死即可
18. StringBuffer url=new StringBuffer("https://open.weixin.qq.com/connect/oauth2/authorize?redirect_uri="+redirect_uri+
19. "&appid="+/*你的appid*/+"&response_type=code&scope=snsapi_base&state=1#wechat_redirect");
20. response.sendRedirect(url.toString());//这里请不要使用get请求单纯的将页面跳转到该url即可
23. }
接下来第二步就好处理了,你可以直接在同一个方法里进行第二步操作,获取用户的openid等信息,也可以在单独写一个方法进行获取。
我的操作是这样的:
@RequestMapping("/login")
public String loginDemo(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException, JSONException {
System.out.println("+++++++微信+++++++"+request.getParameter("code"));
response.setContentType("text/html");
request.setCharacterEncoding("UTF-8");
response.setCharacterEncoding("UTF-8");
String code = request.getParameter("code");//获取code
Map params = new HashMap(16);
//公众号的secret
params.put("secret", "/*你的secret*/");
//公众号的appid
params.put("appid", "/*你的appid*/");
params.put("grant_type", "authorization_code");
params.put("code", request.getParameter("code"));
String result = HttpGetUtil.httpRequestToString(
"https://api.weixin.qq.com/sns/oauth2/access_token", params);
JSONObject jsonObject = new JSONObject(result);
//JSONObject jsonObject = JSONObject.fromObject(result);
String openid = jsonObject.get("openid").toString();
System.out.println("得到的openid为:"+openid);
......
return ...;
}
另外一种使用servlet的实现方式:
当用户用微信进入我们的网页并调用到上面的WxCodeServlet之后,若参数无误,设置的网页授权域名正确,微信就会重定向页面到我们提交的回调地址,同时我们想要的code也会被传过来,这样我们就能从下面这段代码中获取到你想要的openid了。
1. public class WxOpenIdServlet extends HttpServlet {
3. private static final long serialVersionUID = 1L;
5. public void doGet(HttpServletRequest request, HttpServletResponse response)
6. throws ServletException, IOException {
8. response.setContentType("text/html");
10. request.setCharacterEncoding("UTF-8");
11. response.setCharacterEncoding("UTF-8");
12. String code = request.getParameter("code");//获取code
13. Map params = new HashMap();
14. params.put("secret", "/*你的secret*/");
15. params.put("appid", "/*你的appid*/");
16. params.put("grant_type", "authorization_code");
17. params.put("code", code);
18. String result = HttpGetUtil.httpRequestToString(
19. "https://api.weixin.qq.com/sns/oauth2/access_token", params);
20. JSONObject jsonObject = JSONObject.fromObject(result);
22. String openid = jsonObject.get("openid").toString();
23. System.out.println("得到的openid为:"+openid);
24. }
27. public void doPost(HttpServletRequest request, HttpServletResponse response)
28. throws ServletException, IOException {
29. doGet(request, response);
30. }
31. }
在这里补充一下:
有人获取到code后去请求openid却被微信反回了一个错误码"errcode":40125,对应的错误是appsecret无效,可是填写的appsecret与公众平台中的appsecret一致。这个问题在开发时我也遇到过,解决方式是重置appsecret,当初也没在意,现在看来这个问题挺频繁的,所以在这里再补充一下。
至此,如果各个步骤都没有出错的话,控制台就能打印出来刚才通过微信打开我们网页的微信用户对应我们公众号平台的openid了,其实这里获取到的不止用户的openid,还包含了用户的其他信息。
附:上面的方法中用到了一个工具类HttpGetUtil,这里也贴出来,方便大家借鉴。(使用JSONObject需要先导入josn包,这里我也贴出来了吧)
<!--json-->
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>20180813</version>
</dependency>
工具类HttpGetUtil:
public class HttpGetUtil {
public static String httpRequestToString(String url,
Map<String,String> params) {
String result = null;
try {
InputStream is = httpRequestToStream(url, params);
BufferedReader in = new BufferedReader(new InputStreamReader(is,
"UTF-8"));
StringBuffer buffer = new StringBuffer();
String line = "";
while ((line = in.readLine()) != null) {
buffer.append(line);
}
result = buffer.toString();
} catch (Exception e) {
return null;
}
return result;
}
private static InputStream httpRequestToStream(String url,
Map<String, String> params) {
InputStream is = null;
try {
String parameters = "";
boolean hasParams = false;
for(String key : params.keySet()){
String value = URLEncoder.encode(params.get(key), "UTF-8");
parameters += key +"="+ value +"&";
hasParams = true;
}
if(hasParams){
parameters = parameters.substring(0, parameters.length()-1);
}
url += "?"+ parameters;
URL u = new URL(url);
HttpURLConnection conn = (HttpURLConnection) u.openConnection();
conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
conn.setRequestProperty("Accept-Charset", "UTF-8");
conn.setRequestProperty("contentType", "utf-8");
conn.setConnectTimeout(50000);
conn.setReadTimeout(50000);
conn.setDoInput(true);
//设置请求方式,默认为GET
conn.setRequestMethod("GET");
is = conn.getInputStream();
} catch (UnsupportedEncodingException | MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return is;
}
}