授权获取用户信息
1.设置 网页授权获取用户信息
2.获取授权接口 及回调接口代码
package com.hxl.controller;
import com.hxl.utils.wx.SignUtil;
import com.hxl.utils.wx.serviceUtils.OAuthServiceUtils;
import com.hxl.utils.wx.vo.AccessTokenOAuth;
import com.hxl.utils.wx.vo.UserWeiXin;
import io.swagger.annotations.Api;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
/**
* Created by hxl on 2019/9/5.
*/
@Controller
@RequestMapping("wxService")
public class WeixinController {
/**
* 开启服务
* @param request
* @param response
*/
@RequestMapping(method = RequestMethod.GET)
public static void get(HttpServletRequest request, HttpServletResponse response) {
// 微信加密签名,signature结合了开发者填写的token参数和请求中的timestamp参数、nonce参数。
String signature = request.getParameter("signature");
// 时间戳
String timestamp = request.getParameter("timestamp");
// 随机数
String nonce = request.getParameter("nonce");
// 随机字符串
String echostr = request.getParameter("echostr");
PrintWriter out = null;
try {
out = response.getWriter();
// 通过检验signature对请求进行校验,若校验成功则原样返回echostr,否则接入失败
if (SignUtil.checkSignature(signature, timestamp, nonce)) {
out.print(echostr);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
out.close();
out = null;
}
}
/**
* 用户事件处理
* @param request
* @param response
*/
@RequestMapping(method = RequestMethod.POST)
public void post(HttpServletRequest request, HttpServletResponse response) {
try {
request.setCharacterEncoding("UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
response.setCharacterEncoding("UTF-8");
// 调用核心业务类接收消息、处理消息
//String respMessage = coreService.processRequest(request);
// 响应消息
PrintWriter out = null;
try {
out = response.getWriter();
out.print("");
} catch (IOException e) {
e.printStackTrace();
} finally {
out.close();
out = null;
}
}
/**
* 授权验证
* @param request
* @param response
*/
@RequestMapping("authorize")
public void authorize(HttpServletRequest request,HttpServletResponse response) {
String redirectUrl = "https://域名/web/wxService/getUserWeiXin";
//snsapi_base snsapi_userinfo
String url = OAuthServiceUtils.getOauthUrl(redirectUrl,"UTF-8","snsapi_userinfo");
System.out.println(url);
String html = "<script type='text/javascript'>location.href='"+url+"';</script>";
try {
response.getWriter().print(html);
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 回调 授权
* @param code 授权code
* @param state 参数回调
*/
@RequestMapping(value = "/getUserWeiXin")
public String getUserWeiXin(@RequestParam(value = "code") String code, @RequestParam(value = "state", required = false) String state) {
//1.回调 code 和 state
System.out.println("code=" + code + ", state=" + state);
AccessTokenOAuth authToken = OAuthServiceUtils.getOAuthAccessToken(code);
//2.获取 access_token 和 openid
String access_token = authToken.getAccessToken();
String openid = authToken.getOpenid();
System.out.println("access_token=" + access_token+ ", openid=" + openid);
//3.拉取用户信息
UserWeiXin userWeiXin = OAuthServiceUtils.getUserInfoOauth(access_token,openid);
return "user";
}
}
3.OAuthServiceUtils 工具类 (验证授权和用户信息接口)
package com.hxl.utils.wx.serviceUtils;
import com.hxl.utils.wx.Constant.ConstantWeChat;
import com.hxl.utils.wx.StringUtil;
import com.hxl.utils.wx.WeixinUtil;
import com.hxl.utils.wx.vo.AccessTokenOAuth;
import com.hxl.utils.wx.vo.UserWeiXin;
import net.sf.json.JSONObject;
import org.apache.log4j.Logger;
import java.net.URLEncoder;
/**
* 授权 网页授权 和用户信息获取
* Created by hxl on 2019/9/5.
*/
public class OAuthServiceUtils {
public static Logger log = Logger.getLogger(OAuthServiceUtils.class);
/**
* wechat oauth url
*/
public static String OAUTH = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect";
/**
* 通过oauth获取用户详细信息
*/
public static String GET_USER_INFO_OAUTH = "https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN";
/**
* 获取oauth网页认证的token
*/
public static String GET_ACCESS_TOKEN_OAUTH = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code";
/**
* 获得Oauth认证的URL
* @param redirectUrl 跳转的url
* @param charset 字符集格式
* @param scope OAUTH scope
* @return oauth url
*/
public static String getOauthUrl(String redirectUrl,String charset,String scope){
String url = "";
try {
url = OAUTH
.replace("APPID", ConstantWeChat.APPID)
.replace("REDIRECT_URI",
URLEncoder.encode(redirectUrl, charset))
.replace("SCOPE", scope);
} catch (Exception e) {
e.printStackTrace();
}
return url;
}
/**
*
* 获取Access_Token(oAuth认证,此access_token与基础支持的access_token不同)
*
* @param code
* 用户授权后得到的code
* @return AccessTokenOAuth对象
*/
public static AccessTokenOAuth getOAuthAccessToken(String code) {
String url = GET_ACCESS_TOKEN_OAUTH
.replace("APPID", ConstantWeChat.APPID)
.replace("SECRET", ConstantWeChat.APPSECRET)
.replace("CODE", code);
JSONObject jsonObject = WeixinUtil.httpsRequest(url, "POST", null);
AccessTokenOAuth accessTokenOAuth = null;
if (null != jsonObject) {
if (StringUtil.isNotEmpty(jsonObject.get("errcode"))
&& jsonObject.get("errcode") != "0") {
log.error("获取access_token失败 errcode:"
+ jsonObject.getInt("errcode") + ",errmsg:"
+ jsonObject.getString("errmsg"));
} else {
accessTokenOAuth = new AccessTokenOAuth();
accessTokenOAuth.setAccessToken(jsonObject
.getString("access_token"));
accessTokenOAuth.setExpiresIn(jsonObject.getInt("expires_in"));
accessTokenOAuth.setRefreshToken(jsonObject
.getString("refresh_token"));
accessTokenOAuth.setOpenid(jsonObject.getString("openid"));
accessTokenOAuth.setScope(jsonObject.getString("scope"));
}
}
return accessTokenOAuth;
}
/**
* 通过oauth获取用户详细信息
*
* @param token
* @param openid
* @return UserWeiXin对象
*/
public static UserWeiXin getUserInfoOauth(String token, String openid) {
UserWeiXin user = null;
if (token != null) {
String url = GET_USER_INFO_OAUTH.replace("ACCESS_TOKEN", token)
.replace("OPENID", openid);
JSONObject jsonObject = WeixinUtil.httpsRequest(url, "POST", null);
if (null != jsonObject) {
if (StringUtil.isNotEmpty(jsonObject.get("errcode"))
&& jsonObject.get("errcode") != "0") {
log.error("获取用户信息失败 errcode:"
+ jsonObject.getInt("errcode") + ",errmsg:"
+ jsonObject.getString("errmsg"));
} else {
user = new UserWeiXin();
user.setOpenid(jsonObject.getString("openid"));
user.setNickname(jsonObject.getString("nickname"));
user.setHeadimgurl(jsonObject.getString("headimgurl"));
user.setSex(jsonObject.getInt("sex"));
user.setCity(jsonObject.getString("city"));
user.setCountry(jsonObject.getString("country"));
user.setProvince(jsonObject.getString("province"));
user.setLanguage(jsonObject.getString("language"));
user.setPrivilege(jsonObject.getString("privilege"));
}
}
}
return user;
}
}
4. wechat.properties 配置信息 及 ConstantWeChat
#测试号
token=***
appId=***
appSecret=***
encodingAESKey=***
public class ConstantWeChat {
/**
* 与接口配置信息中的Token要一致
*/
public static String TOKEN = ConfigUtil.get("token");
/**
* 第三方用户唯一凭证
*/
public static String APPID = ConfigUtil.get("appId");
/**
* 第三方用户唯一凭证密钥
*/
public static String APPSECRET = ConfigUtil.get("appSecret");
}
读取配置参考: https://blog.youkuaiyun.com/qq_37184877/article/details/100656365
5.WeixinUtil 工具( https 请求) MyX509TrustManager (ssl 证书)
package com.hxl.utils.wx;
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 net.sf.json.JSONObject;
import org.apache.log4j.Logger;
/**
* Created by hxl on 2019/9/5.
*/
public class WeixinUtil {
public static Logger log = Logger.getLogger(WeixinUtil.class);
/**
* 发起https请求并获取结果
*
* @param requestUrl
* 请求地址
* @param requestMethod
* 请求方式(GET、POST)
* @param outputStr
* 提交的数据
* @return JSONObject(通过JSONObject.get(key)的方式获取json对象的属性值)
*/
public static JSONObject httpsRequest(String requestUrl,
String requestMethod, String outputStr) {
JSONObject jsonObject = null;
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();
jsonObject = JSONObject.fromObject(buffer.toString());
} catch (ConnectException ce) {
log.error("server connection timed out.");
} catch (Exception e) {
log.error("https request error:", e);
}
return jsonObject;
}
}
package com.hxl.utils.wx;
import javax.net.ssl.X509TrustManager;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
/**
* 证书信任管理器(用于https请求)
* Created by hxl on 2019/9/5.
*/
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;
}
}
6.示例对象 (授权对象 用户信息对象)
package com.hxl.utils.wx.vo;
import lombok.Data;
/**
*
* 网页授权接口调用凭证 OAuth2.0
* Created by hxl on 2019/9/5.
*/
@Data
public class AccessTokenOAuth {
/**
* 网页授权接口调用凭证,注意:此access_token与基础支持的access_token不同
*/
private String accessToken;
/**
* access_token接口调用凭证超时时间,单位(秒)
*/
private int expiresIn;
/**
* 用户刷新access_token
*/
private String refreshToken;
/**
* 用户唯一标识,请注意,在未关注公众号时,用户访问公众号的网页,也会产生一个用户和公众号唯一的OpenID
*/
private String openid;
/**
* 用户授权的作用域,使用逗号(,)分隔
*/
private String scope;
}
package com.hxl.utils.wx.vo;
import lombok.Data;
import java.util.Date;
/**
* Created by hxl on 2019/9/5.
*/
@Data
public class UserWeiXin {
/**
* 用户是否订阅该公众号标识,值为0时,代表此用户没有关注该公众号,拉取不到其余信息。
*/
private Integer subscribe;
/**
* 用户的标识,对当前公众号唯一
*/
private String openid;
/**
* 用户的昵称
*/
private String nickname;
/**
* 用户的性别,值为1时是男性,值为2时是女性,值为0时是未知
*/
private Integer sex;
/**
* 用户所在城市
*/
private String city;
/**
* 用户所在国家
*/
private String country;
/**
* 用户所在省份
*/
private String province;
/**
* 用户的语言,简体中文为zh_CN
*/
private String language;
/**
* 用户头像,最后一个数值代表正方形头像大小
* (有0、46、64、96、132数值可选,0代表640*640正方形头像),
* 用户没有头像时该项为空
*/
private String headimgurl;
/**
* 用户关注时间,为时间戳。如果用户曾多次关注,则取最后关注时间
*/
private Date subscribe_time;
/**
* 微信特权
* @return
*/
private String privilege;
}
7.调用文档说明
文档说明:https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/Wechat_webpage_authorization.html
获取详细用户信息需要非静默授权。
找到 “ 网页授权”接口参考
找到 “ 获取用户基本信息(包括UnionID机制)”接口参考