1教馆、配置微信公眾平臺(tái)服務(wù)器配置
校驗(yàn)?zāi)K代碼:
- SignUtil (校驗(yàn)幫助類)
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
/**
*類名: SignUtil </br>
*描述: 檢驗(yàn)signature 工具類 </br>
*開(kāi)發(fā)人員: souvc </br>
*創(chuàng)建時(shí)間: 2015-9-29 </br>
*發(fā)布版本:V1.0 </br>
*/
public class SignUtil {
// 與接口配置信息中的Token要一致
private static String token = "souvcweixin";
/**
* 方法名:checkSignature</br>
* 詳述:驗(yàn)證簽名</br>
* 開(kāi)發(fā)人員:souvc</br>
* 創(chuàng)建時(shí)間:2015-9-29 </br>
* @param signature
* @param timestamp
* @param nonce
* @return
* @throws
*/
public static boolean checkSignature(String signature, String timestamp,String nonce) {
// 1.將token鳖擒、timestamp唉铜、nonce三個(gè)參數(shù)進(jìn)行字典序排序
String[] arr = new String[] { ConfigUtil.getParameter("wx_token"), timestamp, nonce };
Arrays.sort(arr);
// 2. 將三個(gè)參數(shù)字符串拼接成一個(gè)字符串進(jìn)行sha1加密
StringBuilder content = new StringBuilder();
for (int i = 0; i < arr.length; i++) {
content.append(arr[i]);
}
MessageDigest md = null;
String tmpStr = null;
try {
md = MessageDigest.getInstance("SHA-1");
// 將三個(gè)參數(shù)字符串拼接成一個(gè)字符串進(jìn)行sha1加密
byte[] digest = md.digest(content.toString().getBytes());
tmpStr = byteToStr(digest);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
content = null;
// 3.將sha1加密后的字符串可與signature對(duì)比嵌施,標(biāo)識(shí)該請(qǐng)求來(lái)源于微信
return tmpStr != null ? tmpStr.equals(signature.toUpperCase()) : false;
}
/**
* 方法名:byteToStr</br>
* 詳述:將字節(jié)數(shù)組轉(zhuǎn)換為十六進(jìn)制字符串</br>
* 開(kāi)發(fā)人員:souvc </br>
* 創(chuàng)建時(shí)間:2015-9-29 </br>
* @param byteArray
* @return
* @throws
*/
private static String byteToStr(byte[] byteArray) {
String strDigest = "";
for (int i = 0; i < byteArray.length; i++) {
strDigest += byteToHexStr(byteArray[i]);
}
return strDigest;
}
/**
* 方法名:byteToHexStr</br>
* 詳述:將字節(jié)轉(zhuǎn)換為十六進(jìn)制字符串</br>
* 開(kāi)發(fā)人員:souvc</br>
* 創(chuàng)建時(shí)間:2015-9-29 </br>
* @param mByte
* @return
* @throws
*/
private static String byteToHexStr(byte mByte) {
char[] Digit = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A','B', 'C', 'D', 'E', 'F' };
char[] tempArr = new char[2];
tempArr[0] = Digit[(mByte >>> 4) & 0X0F];
tempArr[1] = Digit[mByte & 0X0F];
String s = new String(tempArr);
return s;
}
}
- WeiXinConteroller (接收來(lái)自微信服務(wù)的請(qǐng)求)
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
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.ResponseBody;
import com.sinsinet.module.Config;
import com.sinsinet.module.SNSUserInfo;
import com.sinsinet.module.WeixinOauth2Token;
import com.sinsinet.util.ConfigUtil;
import com.sinsinet.util.SignUtil;
import com.sinsinet.util.WeixinUtil;
@Controller
@RequestMapping("/weixin")
public class WeiXinConteroller {
/**
* 接收來(lái)自微信服務(wù)的請(qǐng)求
*/
@RequestMapping(method = RequestMethod.GET)
@ResponseBody
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 微信加密簽名
String signature = request.getParameter("signature");
// 時(shí)間戳
String timestamp = request.getParameter("timestamp");
// 隨機(jī)數(shù)
String nonce = request.getParameter("nonce");
// 隨機(jī)字符串
String echostr = request.getParameter("echostr");
PrintWriter out = response.getWriter();
// 通過(guò)檢驗(yàn)signature對(duì)請(qǐng)求進(jìn)行校驗(yàn),若校驗(yàn)成功則原樣返回echostr豪直,表示接入成功,否則接入失敗
if (SignUtil.checkSignature(signature, timestamp, nonce)) {
out.print(echostr);
}
out.close();
out = null;
}
}
2度秘、網(wǎng)頁(yè)授權(quán)獲取用戶基本信息
- 點(diǎn)擊修改進(jìn)入功能設(shè)置
-
點(diǎn)擊設(shè)置 設(shè)置授權(quán)回調(diào)頁(yè)面域名
微信網(wǎng)頁(yè)授權(quán)的詳細(xì)代碼
- web.xml 配置
<!-- 微信授權(quán) - start -->
<servlet>
<servlet-name>oauthServlet</servlet-name>
<servlet-class>com.sinsinet.service.OAuthServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>oauthServlet</servlet-name>
<url-pattern>*.jsp</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<!-- 微信授權(quán) - end-->
- OAuthServlet
import java.io.IOException;
import java.util.Date;
import javax.annotation.Resource;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.sinsinet.mapper.UserMapper;
import com.sinsinet.module.SNSUserInfo;
import com.sinsinet.module.User;
import com.sinsinet.module.WeixinOauth2Token;
import com.sinsinet.util.CommonUtil;
import com.sinsinet.util.ConfigUtil;
import com.sinsinet.util.TokenUtil;
import com.sinsinet.util.WeixinUtil;
/**
* 類名: OAuthServlet </br>
* 描述: 授權(quán)后的回調(diào)請(qǐng)求處理 </br>
* 開(kāi)發(fā)人員: souvc </br>
* 創(chuàng)建時(shí)間: 2015-11-27 </br>
* 發(fā)布版本:V1.0 </br>
*/
public class OAuthServlet extends HttpServlet {
@Resource
UserMapper mUserMapper;
private static final long serialVersionUID = -1847238807216447030L;
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("utf-8");
response.setCharacterEncoding("utf-8");
// 用戶同意授權(quán)后,能獲取到code
String code = request.getParameter("code");
String state = request.getParameter("state");
// 用戶同意授權(quán)
if (!"authdeny".equals(code)) {
// 獲取網(wǎng)頁(yè)授權(quán)access_token
WeixinOauth2Token weixinOauth2Token = WeixinUtil.getOauth2AccessToken(ConfigUtil.getParameter("wx_AppId"),ConfigUtil.getParameter("wx_AppSecret"),code);
// 網(wǎng)頁(yè)授權(quán)接口訪問(wèn)憑證
String accessToken = weixinOauth2Token.getAccessToken();
// 用戶標(biāo)識(shí)
String openId = weixinOauth2Token.getOpenId();
// 獲取用戶信息
SNSUserInfo snsUserInfo = WeixinUtil.getSNSUserInfo(accessToken, openId);
User user = mUserMapper.findByOpenid(openId);
if (user == null) {
user.setOpenid(snsUserInfo.getOpenId());
user.setWxName(snsUserInfo.getNickname());
user.setSex(snsUserInfo.getSex());
user.setRole(3);
user.setCreateTime(new Date());
mUserMapper.insert(user);
user = mUserMapper.findByOpenid(openId);
}
// 設(shè)置要傳遞的參數(shù)
request.setAttribute("user", user);
request.setAttribute("state", state);
}
// 跳轉(zhuǎn)到index.jsp
request.getRequestDispatcher("index.jsp").forward(request, response);
}
}
- WeixinOauth2Token
public class WeixinOauth2Token {
// 網(wǎng)頁(yè)授權(quán)接口調(diào)用憑證
private String accessToken;
// 憑證有效時(shí)長(zhǎng)
private int expiresIn;
// 用于刷新憑證
private String refreshToken;
// 用戶標(biāo)識(shí)
private String openId;
// 用戶授權(quán)作用域
private String scope;
public String getAccessToken() {
return accessToken;
}
public void setAccessToken(String accessToken) {
this.accessToken = accessToken;
}
public int getExpiresIn() {
return expiresIn;
}
public void setExpiresIn(int expiresIn) {
this.expiresIn = expiresIn;
}
public String getRefreshToken() {
return refreshToken;
}
public void setRefreshToken(String refreshToken) {
this.refreshToken = refreshToken;
}
public String getOpenId() {
return openId;
}
public void setOpenId(String openId) {
this.openId = openId;
}
public String getScope() {
return scope;
}
public void setScope(String scope) {
this.scope = scope;
}
}
- SNSUserInfo
import java.util.List;
/**
* 類名: SNSUserInfo </br>
* 描述: 通過(guò)網(wǎng)頁(yè)授權(quán)獲取的用戶信息 </br>
* 開(kāi)發(fā)人員: souvc </br>
* 創(chuàng)建時(shí)間: 2015-11-27 </br>
* 發(fā)布版本:V1.0 </br>
*/
public class SNSUserInfo {
// 用戶標(biāo)識(shí)
private String openId;
// 用戶昵稱
private String nickname;
// 性別(1是男性,2是女性剑梳,0是未知)
private int sex;
// 國(guó)家
private String country;
// 省份
private String province;
// 城市
private String city;
// 用戶頭像鏈接
private String headImgUrl;
// 用戶特權(quán)信息
private List<String> privilegeList;
public String getOpenId() {
return openId;
}
public void setOpenId(String openId) {
this.openId = openId;
}
public String getNickname() {
return nickname;
}
public void setNickname(String nickname) {
this.nickname = nickname;
}
public int getSex() {
return sex;
}
public void setSex(int sex) {
this.sex = sex;
}
public String getCountry() {
return country;
}
public void setCountry(String country) {
this.country = country;
}
public String getProvince() {
return province;
}
public void setProvince(String province) {
this.province = province;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public String getHeadImgUrl() {
return headImgUrl;
}
public void setHeadImgUrl(String headImgUrl) {
this.headImgUrl = headImgUrl;
}
public List<String> getPrivilegeList() {
return privilegeList;
}
public void setPrivilegeList(List<String> privilegeList) {
this.privilegeList = privilegeList;
}
}
- WeixinUtil
import java.awt.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.sinsinet.module.SNSUserInfo;
import com.sinsinet.module.WeixinOauth2Token;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
public class WeixinUtil {
static Logger log = LoggerFactory.getLogger(WeixinUtil.class);
/**
* 獲取網(wǎng)頁(yè)授權(quán)憑證
*
* @param appId 公眾賬號(hào)的唯一標(biāo)識(shí)
* @param appSecret 公眾賬號(hào)的密鑰
* @param code
* @return WeixinAouth2Token
*/
public static WeixinOauth2Token getOauth2AccessToken(String appId, String appSecret, String code) {
WeixinOauth2Token wat = null;
// 拼接請(qǐng)求地址
String requestUrl = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code";
requestUrl = requestUrl.replace("APPID", appId);
requestUrl = requestUrl.replace("SECRET", appSecret);
requestUrl = requestUrl.replace("CODE", code);
// 獲取網(wǎng)頁(yè)授權(quán)憑證
JSONObject jsonObject = CommonUtil.httpsRequest(requestUrl, "GET", null);
if (null != jsonObject) {
try {
wat = new WeixinOauth2Token();
wat.setAccessToken(jsonObject.getString("access_token"));
wat.setExpiresIn(jsonObject.getInt("expires_in"));
wat.setRefreshToken(jsonObject.getString("refresh_token"));
wat.setOpenId(jsonObject.getString("openid"));
wat.setScope(jsonObject.getString("scope"));
} catch (Exception e) {
wat = null;
int errorCode = jsonObject.getInt("errcode");
String errorMsg = jsonObject.getString("errmsg");
log.error("獲取網(wǎng)頁(yè)授權(quán)憑證失敗 errcode:{} errmsg:{}", errorCode, errorMsg);
}
}
return wat;
}
/**
* 通過(guò)網(wǎng)頁(yè)授權(quán)獲取用戶信息
*
* @param accessToken 網(wǎng)頁(yè)授權(quán)接口調(diào)用憑證
* @param openId 用戶標(biāo)識(shí)
* @return SNSUserInfo
*/
@SuppressWarnings( { "deprecation", "unchecked" })
public static SNSUserInfo getSNSUserInfo(String accessToken, String openId) {
SNSUserInfo snsUserInfo = null;
// 拼接請(qǐng)求地址
String requestUrl = "https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID";
requestUrl = requestUrl.replace("ACCESS_TOKEN", accessToken).replace("OPENID", openId);
// 通過(guò)網(wǎng)頁(yè)授權(quán)獲取用戶信息
JSONObject jsonObject = CommonUtil.httpsRequest(requestUrl, "GET", null);
if (null != jsonObject) {
try {
snsUserInfo = new SNSUserInfo();
// 用戶的標(biāo)識(shí)
snsUserInfo.setOpenId(jsonObject.getString("openid"));
// 昵稱
snsUserInfo.setNickname(jsonObject.getString("nickname"));
// 性別(1是男性唆貌,2是女性,0是未知)
snsUserInfo.setSex(jsonObject.getInt("sex"));
// 用戶所在國(guó)家
snsUserInfo.setCountry(jsonObject.getString("country"));
// 用戶所在省份
snsUserInfo.setProvince(jsonObject.getString("province"));
// 用戶所在城市
snsUserInfo.setCity(jsonObject.getString("city"));
// 用戶頭像
snsUserInfo.setHeadImgUrl(jsonObject.getString("headimgurl"));
// 用戶特權(quán)信息
snsUserInfo.setPrivilegeList(JSONArray.toList(jsonObject.getJSONArray("privilege"), List.class));
} catch (Exception e) {
snsUserInfo = null;
int errorCode = jsonObject.getInt("errcode");
String errorMsg = jsonObject.getString("errmsg");
log.error("獲取用戶信息失敗 errcode:{} errmsg:{}", errorCode, errorMsg);
}
}
return snsUserInfo;
}
}
- 發(fā)送https請(qǐng)求方法(我的放在l了CommonUtil里)
* 發(fā)送https請(qǐng)求
*
* @param requestUrl 請(qǐng)求地址
* @param requestMethod 請(qǐng)求方式(GET垢乙、POST)
* @param outputStr 提交的數(shù)據(jù)
* @return JSONObject(通過(guò)JSONObject.get(key)的方式獲取json對(duì)象的屬性值)
*/
public static JSONObject httpsRequest(String requestUrl, String requestMethod, String outputStr) {
JSONObject jsonObject = null;
try {
// 創(chuàng)建SSLContext對(duì)象锨咙,并使用我們指定的信任管理器初始化
TrustManager[] tm = { new MyX509TrustManager() };
SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE");
sslContext.init(null, tm, new java.security.SecureRandom());
// 從上述SSLContext對(duì)象中得到SSLSocketFactory對(duì)象
SSLSocketFactory ssf = sslContext.getSocketFactory();
URL url = new URL(requestUrl);
HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
conn.setSSLSocketFactory(ssf);
conn.setDoOutput(true);
conn.setDoInput(true);
conn.setUseCaches(false);
// 設(shè)置請(qǐng)求方式(GET/POST)
conn.setRequestMethod(requestMethod);
// 當(dāng)outputStr不為null時(shí)向輸出流寫數(shù)據(jù)
if (null != outputStr) {
OutputStream outputStream = conn.getOutputStream();
// 注意編碼格式
outputStream.write(outputStr.getBytes("UTF-8"));
outputStream.close();
}
// 從輸入流讀取返回內(nèi)容
InputStream inputStream = conn.getInputStream();
InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8");
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
String str = null;
StringBuffer buffer = new StringBuffer();
while ((str = bufferedReader.readLine()) != null) {
buffer.append(str);
}
// 釋放資源
bufferedReader.close();
inputStreamReader.close();
inputStream.close();
inputStream = null;
conn.disconnect();
jsonObject = JSONObject.fromObject(buffer.toString());
} catch (ConnectException ce) {
log.error("連接超時(shí):{}", ce);
} catch (Exception e) {
log.error("https請(qǐng)求異常:{}", e);
}
return jsonObject;
}
- MyX509TrustManager (信任管理器 )
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import javax.net.ssl.X509TrustManager;
/**
* 類名: MyX509TrustManager </br>
* 描述:信任管理器 </br>
* 開(kāi)發(fā)人員: souvc </br>
* 創(chuàng)建時(shí)間: 2015-11-27 </br>
* 發(fā)布版本:V1.0 </br>
*/
public class MyX509TrustManager implements X509TrustManager {
// 檢查客戶端證書(shū)
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
// 檢查服務(wù)器端證書(shū)
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
// 返回受信任的X509證書(shū)數(shù)組
public X509Certificate[] getAcceptedIssuers() {
return null;
}
}
3、測(cè)試
- 在微信客戶端中打開(kāi)此鏈接
(1)替換自己的AppID
(2)將redirect_url換成自己的授權(quán)請(qǐng)求鏈接URL追逮。注意這個(gè)連接需要經(jīng)過(guò)UTF-8編碼酪刀。
(3)需要修改scope。需要彈出頁(yè)面則要修改為snsapi_userinfo 钮孵。