微信登录接口
说明
1、接口使用了swagger注解,可以删掉不用;
2、微信登录接口需部署到服务器才能测试访问,成功示例:
pom.xml
<!--okhttp3-->
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>3.10.0</version>
</dependency>
application.yml
wechat:
openUrl: https://api.weixin.qq.com/sns/jscode2session
appId: ***
appSecret: ***
grantType: authorization_code
RestWechatController.java
package com.ruoyi.api.wechat;
import com.ruoyi.api.wechat.domain.WechatLoginVo;
import com.ruoyi.api.wechat.service.IWechatLoginService;
import com.ruoyi.framework.web.controller.BaseController;
import com.ruoyi.framework.web.domain.AjaxResult;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
/**
* 微信授权登录
* @author wangjiao
* @version 1.0
* @date 2020/4/23
*/
@Api(tags = "微信登录相关接口")
@RestController
@RequestMapping("/rest/wechat")
public class RestWechatController extends BaseController {
@Autowired
private IWechatLoginService service;
@ApiOperation(value = "微信登录", notes = "登录实体Vo部分必填")
@ApiImplicitParam(name = "wechatLoginVo", value = "登录实体Vo")
@PostMapping("/login")
@ResponseBody
public AjaxResult login(@RequestBody WechatLoginVo entity) {
return AjaxResult.success(service.login(entity));
}
}
IWechatLoginService.java
package com.ruoyi.api.wechat.service;
import com.ruoyi.api.wechat.domain.WechatLoginVo;
/**
* @author wangjiao
* @version 1.0
* @date 2020/4/23
*/
public interface IWechatLoginService {
WechatLoginVo login(WechatLoginVo entity);
}
WechatLoginServiceImpl.java
package com.ruoyi.api.wechat.service;
import com.alibaba.fastjson.JSONObject;
import com.aliyun.oss.ServiceException;
import com.ruoyi.admin.wechat.service.IEpWechatUserService;
import com.ruoyi.api.wechat.domain.EpWechatUser;
import com.ruoyi.api.wechat.domain.WechatLoginVo;
import com.ruoyi.api.wechat.util.WechatHttpUtils;
import com.ruoyi.api.wechat.util.WechatUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import java.io.IOException;
import java.util.Map;
import java.util.Objects;
/**
* @author wangjiao
* @version 1.0
* @date 2020/4/23
*/
@Slf4j
@Service
public class WechatLoginServiceImpl implements IWechatLoginService {
@Autowired
private IEpWechatUserService service;
@Value("${wechat.appId}")
private String appId;
@Value("${wechat.appSecret}")
private String secret;
@Value("${wechat.grantType}")
private String grantType;
@Value("${wechat.openUrl}")
private String wechatOpenUrl;
@Override
public WechatLoginVo login(WechatLoginVo wechatLoginVo) {
try {
log.info("loginByCode进入=============" + wechatLoginVo.toString());
WechatLoginVo returnVo = new WechatLoginVo();
if (StringUtils.isBlank(wechatLoginVo.getCode())) {
throw new RuntimeException("授权码不能为空");
}
Map<String, Object> wxResult = getOpenIdByHttpClient(wechatLoginVo.getCode());
log.info(wxResult.toString());
String sessionkey = "";
if (wxResult.containsKey("session_key")) {
sessionkey = wxResult.get("session_key").toString();
}
String openid = "";
if (wxResult.containsKey("openid")) {
openid = wxResult.get("openid").toString();
log.info(openid);
/**
* 如果已经注册过了 直接返回数据
*/
EpWechatUser epWechatUser = service.selectEntityByOpenId(openid);
if (Objects.nonNull(epWechatUser)) {
BeanUtils.copyProperties(epWechatUser, returnVo);
return returnVo;
}
}
if (StringUtils.isBlank(wechatLoginVo.getEncryptedData()) || StringUtils.isBlank(wechatLoginVo.getIv())) {
throw new RuntimeException("加密的数据不能为空");
}
if (StringUtils.isBlank(sessionkey)) {
throw new RuntimeException("授权信息有误");
}
JSONObject userInfo = WechatUtil.getUserInfo(wechatLoginVo.getEncryptedData(), sessionkey, wechatLoginVo.getIv());
log.info(userInfo.toJSONString());
returnVo = JSONObject.toJavaObject(userInfo, WechatLoginVo.class);
//注册账号
int result=insertWechatUser(returnVo);
if(result>0){
return returnVo;
}
throw new RuntimeException("注册账号失败");
} catch (IOException e) {
e.printStackTrace();
}
throw new RuntimeException("登录失败,服务器错误");
}
public Map<String, Object> getOpenIdByHttpClient(String code) throws IOException {
WechatHttpUtils httpUtil = new WechatHttpUtils();
String result = httpUtil.header("X-Requested-With", "XMLHttpRequest")
.data("appid", appId)
.data("secret", secret)
.data("js_code", code)
.data("grant_type", grantType)
.url(wechatOpenUrl)
.get();
Map<String, Object> map = JSONObject.parseObject(result, Map.class);
if (!map.containsKey("openid")) {
throw new ServiceException("错误信息:" + map.get("errmsg"));
}
return map;
}
private int insertWechatUser(WechatLoginVo wechatLoginVo) {
EpWechatUser entity = new EpWechatUser();
BeanUtils.copyProperties(wechatLoginVo, entity);
return service.insertEntity(entity);
}
}
WechatUtil.java
package com.ruoyi.api.wechat.util;
import com.alibaba.fastjson.JSONObject;
import com.sun.org.apache.xerces.internal.impl.dv.util.Base64;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import java.security.Security;
import java.util.Arrays;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.AlgorithmParameters;
/**
* @author wangjiao
* @version 1.0
* @date 2020/4/23
*/
public class WechatUtil {
public static JSONObject getUserInfo(String encryptedData, String sessionKey, String iv) {
// 被加密的数据
byte[] dataByte = Base64.decode(encryptedData);
// 加密秘钥
byte[] keyByte = Base64.decode(sessionKey);
// 偏移量
byte[] ivByte = Base64.decode(iv);
try {
// 如果密钥不足16位,那么就补足. 这个if 中的内容很重要
int base = 16;
if (keyByte.length % base != 0) {
int groups = keyByte.length / base + (keyByte.length % base != 0 ? 1 : 0);
byte[] temp = new byte[groups * base];
Arrays.fill(temp, (byte) 0);
System.arraycopy(keyByte, 0, temp, 0, keyByte.length);
keyByte = temp;
}
// 初始化
Security.addProvider(new BouncyCastleProvider());
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding", "BC");
SecretKeySpec spec = new SecretKeySpec(keyByte, "AES");
AlgorithmParameters parameters = AlgorithmParameters.getInstance("AES");
parameters.init(new IvParameterSpec(ivByte));
cipher.init(Cipher.DECRYPT_MODE, spec, parameters);// 初始化
byte[] resultByte = cipher.doFinal(dataByte);
if (null != resultByte && resultByte.length > 0) {
String result = new String(resultByte, "UTF-8");
return JSONObject.parseObject(result);
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
WechatHttpUtils.java
package com.ruoyi.api.wechat.util;
import lombok.extern.slf4j.Slf4j;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import org.apache.commons.lang.StringUtils;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.TimeUnit;
/**
* @author wangjiao
* @version 1.0
* @date 2020/4/29
*/
@Slf4j
public class WechatHttpUtils {
private Map<String, String> headers = new LinkedHashMap<>();
private Map<String, String> queryParas = new LinkedHashMap<>();
private String url = "";
private Request.Builder requestBuilder = new Request.Builder();
private OkHttpClient.Builder httpClient = new OkHttpClient().newBuilder().connectTimeout(10, TimeUnit.SECONDS).readTimeout(60, TimeUnit.SECONDS).writeTimeout(30, TimeUnit.SECONDS);
public WechatHttpUtils header(String key, String value) {
this.headers.put(key, value);
return this;
}
public WechatHttpUtils data(String key, String value) {
this.queryParas.put(key, value);
return this;
}
public WechatHttpUtils url(String url) {
this.url = url;
return this;
}
/**
* Send GET request
*
* @throws IOException
*/
public String get() throws IOException {
if (StringUtils.isEmpty(url)) {
log.error("URL为空");
return "";
}
requestBuilder.url(buildUrlWithQueryString(url, queryParas));
for (Entry<String, String> entry : headers.entrySet()) {
requestBuilder.addHeader(entry.getKey(), entry.getValue());
}
Request request = requestBuilder.build();
Response response = httpClient.build().newCall(request).execute();
if (!response.isSuccessful()) {
throw new IOException("GET请求服务器端错误: " + response);
}
return response.body().string();
}
/**
* Build queryString of the url
*/
private static String buildUrlWithQueryString(String url, Map<String, String> queryParas) {
if (queryParas == null || queryParas.isEmpty()) {
return url;
}
StringBuffer sb = new StringBuffer(url);
boolean isFirst;
if (!url.contains("?")) {
isFirst = true;
sb.append("?");
} else {
isFirst = false;
}
for (Entry<String, String> entry : queryParas.entrySet()) {
if (isFirst) {
isFirst = false;
} else {
sb.append("&");
}
String key = entry.getKey();
String value = entry.getValue();
if (StringUtils.isEmpty(value)) {
try {
value = URLEncoder.encode(value, "UTF-8");
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
}
sb.append(key).append("=").append(value);
}
return sb.toString();
}
}