小程序API
https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/login.html
public class WeChatAppLoginReq
{
private String code;
private String rawData;
private String encryptedData;
private String iv;
private String signature;
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getRawData() {
return rawData;
}
public void setRawData(String rawData) {
this.rawData = rawData;
}
public String getEncryptedData() {
return encryptedData;
}
public void setEncryptedData(String encryptedData) {
this.encryptedData = encryptedData;
}
public String getIv() {
return iv;
}
public void setIv(String iv) {
this.iv = iv;
}
public String getSignature() {
return signature;
}
public void setSignature(String signature) {
this.signature = signature;
}
}
import java.io.UnsupportedEncodingException;
import java.security.AlgorithmParameters;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.Security;
import java.util.Date;
import java.util.Map;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.jose4j.base64url.Base64;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.xiaoyi.sns.bean.dto.req.WeChatAppLoginReq;
import com.xiaoyi.sns.bean.po.spo.UserInfoPo;
import com.xiaoyi.sns.business.constant.Constants.UserType;
import com.xiaoyi.sns.business.impl.spo.UserInfoBiz;
import com.xiaoyi.sns.common.constant.ResponseMsg;
import com.xiaoyi.sns.common.exception.SystemException;
import com.xiaoyi.sns.common.util.HmacUtil;
/**
* Project Name: sns-business
* File Name: WeAppLoginBiz.java
* Date: 2017年1月13日下午1:06:17
* Author: [email protected]
* Explain: 微信小程序登录
*/
@Component
public class WeChatAppLoginBiz
{
private static final Logger logger = LoggerFactory.getLogger(WeChatAppLoginBiz.class);
@Autowired
private UserInfoBiz userInfoBiz;
public static boolean initialized = false;
private static final String APPID = "wx3c************b8";
private static final String SECRET = "75324***************500ae89726";
public Map login(WeChatAppLoginReq req)
{
//获取 session_key 和 openId
String url = "https://api.weixin.qq.com/sns/jscode2session?appid="+APPID+"&secret="+SECRET+"&js_code="+req.getCode()+"&grant_type=authorization_code";
RestTemplate restTemplate = new RestTemplate();
ResponseEntity responseEntity = restTemplate.exchange(url, HttpMethod.GET, null, String.class);
if(responseEntity != null && responseEntity.getStatusCode() == HttpStatus.OK)
{
String sessionData = responseEntity.getBody();
logger.info("sessionData = "+ sessionData);
JSONObject jsonObj = JSON.parseObject(sessionData);
String openId = jsonObj.getString("openid");
String sessionKey = jsonObj.getString("session_key");
String signature = HmacUtil.SHA1(req.getRawData()+sessionKey);
if(!signature.equals(req.getSignature()))
{
logger.info(" req signature="+req.getSignature());
logger.info(" java signature="+req.getSignature());
throw new SystemException(ResponseMsg.WECHAT_LOGIN_SIGNATURE_ERROR);
}
byte[] resultByte = null;
try {
resultByte = decrypt(Base64.decode(req.getEncryptedData()), Base64.decode(sessionKey), Base64.decode(req.getIv()));
} catch (Exception e) {
throw new SystemException(ResponseMsg.WECHAT_LOGIN_USER_ERROR);
}
if(null != resultByte && resultByte.length > 0)
{
String userInfoStr = "";
try {
userInfoStr = new String(resultByte, "UTF-8");
} catch (UnsupportedEncodingException e)
{
logger.error(e.getMessage());
}
logger.info("userInfo = "+ userInfoStr);
JSONObject userInfoObj = JSON.parseObject(userInfoStr);
UserInfoPo userPo = new UserInfoPo();
userPo.setName(userInfoObj.getString("nickName"));
userPo.setCreatedTime(new Date());
userPo.setGender(userInfoObj.getString("gender"));
userPo.setIcon(userInfoObj.getString("avatarUrl"));
userPo.setLoginId(userInfoObj.getString("unionId"));
userPo.setType((short)UserType.WeiXin);
userPo.setLoginType(UserType.WeChatApp);
//userPo.setNation(userInfoObj.getString("city"));
//userInfoObj.getString("city");
//userInfoObj.getString("province");
//userInfoObj.getString("country");
Map data = userInfoBiz.insertOrUpdate(userPo);
return data;
}else
{
throw new SystemException(ResponseMsg.WECHAT_LOGIN_USER_ERROR);
}
}else
{
throw new SystemException(ResponseMsg.WECHAT_LOGIN_CODE_ERROR);
}
}
private byte[] decrypt(byte[] content, byte[] keyByte, byte[] ivByte) throws InvalidAlgorithmParameterException {
initialize();
try {
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
Key sKeySpec = new SecretKeySpec(keyByte, "AES");
cipher.init(Cipher.DECRYPT_MODE, sKeySpec, generateIV(ivByte));// 初始化
byte[] result = cipher.doFinal(content);
return result;
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
} catch (NoSuchProviderException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
public static void initialize(){
if (initialized) return;
Security.addProvider(new BouncyCastleProvider());
initialized = true;
}
//生成iv
public static AlgorithmParameters generateIV(byte[] iv) throws Exception{
AlgorithmParameters params = AlgorithmParameters.getInstance("AES");
params.init(new IvParameterSpec(iv));
return params;
}
}
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public class HmacUtil {
public static String SHA1(String str){
try {
//指定sha1算法
MessageDigest digest = MessageDigest.getInstance("SHA-1");
digest.update(str.getBytes());
//获取字节数组
byte messageDigest[] = digest.digest();
// Create Hex String
StringBuffer hexString = new StringBuffer();
// 字节数组转换为 十六进制 数
for (int i = 0; i < messageDigest.length; i++) {
String shaHex = Integer.toHexString(messageDigest[i] & 0xFF);
if (shaHex.length() < 2) {
hexString.append(0);
}
hexString.append(shaHex);
}
return hexString.toString().toLowerCase();
} catch (NoSuchAlgorithmException e) {
return "";
}
}
}