思路:
1.前端生成随机字符串(有数字或字母组成,最好不要有特殊字符,不是所有的特殊字符都支持)
2.PC端调用后端接口,获取小程序二维码,并开始轮询访问接口获取小程序授权的信息
3.微信扫码登录,获取包含在二维码中的参数key(上面的随机字符串),将key和用户信息作为请求参数,调用授权接口
public WxTokenResponse getToken() {
if (wxTokenResponse != null &&
!StringUtils.isEmpty(wxTokenResponse.getAccessToken())) {
Date curDate = new Date();
int span = (int) ((curDate.getTime() - updateTime.getTime()) / 1000);
if (span < wxTokenResponse.getExpiresIn() - 15) {
return wxTokenResponse;
}
}
Map<String, Object> params = new HashMap<String, Object>();
params.put("grant_type", "client_credential");
params.put("appid", wxPayConfig.getAppid());
params.put("secret", wxPayConfig.getSecret());
wxTokenResponse = null;
String jsonStr = apiService.invokeGet(weChartConfig.getUrl(), "cgi-bin/token", null, params);
if (!StringUtils.isEmpty(jsonStr)) {
wxTokenResponse = JSONObject.parseObject(jsonStr, new TypeReference<WxTokenResponse>() {
});
updateTime = new Date();
return wxTokenResponse;
}
return null;
}
/**
*
* @param request
* @param resp
* @param key
* @param path 不传的话,默认跳转小程序的主页,只有在跳转的页面才能获得自定义的参数
*/
public void getAppletCodeStream(HttpServletRequest request, HttpServletResponse resp, String key, String path) {
wxTokenResponse = getToken();
String accessToken = wxTokenResponse.getAccessToken();
//获取小程序码
String codeUrl = "https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=ACCESS_TOKEN"
.replace("ACCESS_TOKEN", accessToken);
Map<String, Object> map = new HashMap<>();
map.put("scene", key);
if (path != null && !path.equals("")) {
map.put("page", key);
}
try {
CloseableHttpResponse response = null;
try {
ObjectMapper objectMapper = new ObjectMapper();
HttpPost httpPost = new HttpPost(codeUrl);
httpPost.addHeader("Content-type", "application/json; charset=utf-8");
httpPost.setEntity(new StringEntity(objectMapper.writeValueAsString(map),
ContentType.create("text/json", "UTF-8")));
response = HttpClients.createDefault().execute(httpPost);
if (response.getStatusLine().getStatusCode() == 200) {
HttpEntity entity = response.getEntity();
if (entity != null) {
//这里不一定需要转为byte,根据你的项目自己选择
BufferedImage read = ImageIO.read(entity.getContent());
ImageIO.write(read, "JPEG", resp.getOutputStream());
}
}
} finally {
if (response != null) {
response.close();
}
}
} catch (Exception e) {
LoggerUtil.logError("调用HttpUtils.sendPostRequest Exception, url=" + codeUrl + ",map=" + map, e);
}
}
private static final Map<String, UserToken> AUTH_KEY = new ConcurrentHashMap();
@ApiOperation(value = "获取小程序二维码图片流", notes = "", produces = "application/json")
@RequestMapping(value = "/getAppletCodeStream", method = RequestMethod.POST)
public void getAppletCodeStream(HttpServletRequest request, HttpServletResponse response,
@ApiParam(name = "key", value = "唯一的识别码", required = true) @RequestParam String key,
@ApiParam(name = "path", value = "路径", required = true) @RequestParam String path) throws Exception {
//设置相应类型,告诉浏览器输出的内容为图片
response.setContentType("image/jpeg");
//设置响应头信息,告诉浏览器不要缓存此内容
response.setHeader("Pragma", "No-cache");
response.setHeader("Cache-Control", "no-cache");
response.setDateHeader("Expire", 0);
response.setHeader("key", request.getSession().getId());
wxCommonService.getAppletCodeStream(request, response, key, path);
}
@ApiOperation(value = "9-小程序授权登录", notes = "", produces = "application/json")
@RequestMapping(value = "/appletPutAuth", method = RequestMethod.POST)
public Response<String> appletPutAuth(
@ApiParam(name = "request", value = "请求参数", required = true) @RequestBody Request<TokenQuery> request) throws Exception {
TokenQuery entity = request.getEntity();
ParamUtil.INSTANCE.checkObjectNull(entity, "entity")
.checkStrNull(entity.getKey(), "key")
.checkObjectNull(entity.getToken(), "token");
UserToken token = entity.getToken();
Long expire = System.currentTimeMillis() + 60 * 1000;
token.setExpire(expire);
AUTH_KEY.put(entity.getKey(), entity.getToken());
return ResponseUtil.outSuccess();
}
@ApiOperation(value = "10-获取小程序授权", notes = "", produces = "application/json")
@RequestMapping(value = "/getAppletAuth")
public Response<UserToken> getAppletAuth(
@ApiParam(name = "key", value = "唯一的识别码", required = true) @RequestParam String key) throws Exception {
ParamUtil.INSTANCE.checkStrNull(key, "key");
if (!AUTH_KEY.containsKey(key)) {
throw new CustomerException("key已经过期");
}
UserToken userToken = AUTH_KEY.get(key);
if (userToken.getExpire() < System.currentTimeMillis()) {
throw new CustomerException("key已经过期");
}
AUTH_KEY.remove(key);
return ResponseUtil.out(userToken);
}
@Scheduled(cron = "0 0/1 * * * ?")
private void clearnAuthKey() {
for (String key : AUTH_KEY.keySet()) {
UserToken userToken = AUTH_KEY.get(key);
if (userToken.getExpire() < System.currentTimeMillis()) {
AUTH_KEY.remove(key);
}
}
}