Created
February 23, 2019 14:10
-
-
Save Ericwyn/03eda7c3b8da0625c3eaad596345a39c to your computer and use it in GitHub Desktop.
微信登录获取 OpenId
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.besfim.wxpay.controller; | |
import com.alibaba.fastjson.JSONObject; | |
import com.besfim.wxpay.utils.HttpUtils; | |
import com.besfim.wxpay.utils.SHA1; | |
import com.besfim.wxpay.utils.obj.ResJson; | |
import org.apache.http.HttpException; | |
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 org.springframework.web.bind.annotation.ResponseBody; | |
import java.io.IOException; | |
import java.net.URLEncoder; | |
import javax.servlet.http.HttpServletRequest; | |
import okhttp3.OkHttpClient; | |
import okhttp3.Request; | |
import okhttp3.Response; | |
/** | |
* | |
* 微信公众号开发,获取 openid 之类的 | |
* | |
* 微信公众号鉴权如下 | |
* | |
* - 访问某个 login 接口(服务器提供),这是个 URL_A | |
* - 该接口负责拼接出一个 wx 的 url,让用户跳转,这个 url 带有一个跳转的 URL_B | |
* - 用户跳转到 wx 的 url,这个 url 会在微信手机端提示用户鉴权, | |
* 用户允许之后,会跳转到 URL_B?code={CODE} | |
* - URL_B 是一个接口,负责接受 CODE 参数,然后将 CODE 参数带上 appid 和 secret 等 | |
* 向微信官方服务器换取该用户的 OpenId,至此该用户完成登录 | |
* | |
* Created by Ericwyn on 19-2-18. | |
*/ | |
@Controller | |
public class WechatController { | |
// // 正式微信公众号 id 和 secret | |
private static final String appid="openid"; | |
private static final String secret="secret"; | |
// //正式部署时候的域名,关系到能够成功跳转微信获取 openid 的接口 | |
private static final String runDomain = "https://wx.meetwhy.com"; | |
// 一个中途转跳的 URL,用户在允许微信鉴权之后,跳转到 URL?code=CODE | |
private static final String URI_REDIRECT = "/user/wx/code"; | |
private OkHttpClient httpClient = HttpUtils.getClient(); | |
/** | |
* 通过这个地址转跳去微信官方地址,以获取微信登录的 code | |
* 并在之后跳转到正式登录接口 | |
* | |
* @return | |
*/ | |
@RequestMapping("/user/wx/login") | |
public String redirectToWechat(){ | |
return "redirect:https://open.weixin.qq.com/connect/oauth2/authorize?appid="+appid+"&redirect_uri="+ URLEncoder.encode(runDomain+ URI_REDIRECT)+"&response_type=code&scope=snsapi_base&state=STATE#wechat_redirect"; | |
} | |
/** | |
* 获取 Code 之后就访问这个地址 | |
* | |
* | |
* @param request | |
* @return | |
* @throws HttpException | |
* @throws IOException | |
*/ | |
@RequestMapping(value = URI_REDIRECT) | |
public String wexinRegister(HttpServletRequest request) throws IOException { | |
System.out.println("收到微信注册请求"); | |
String openid ; | |
//用户微信登录获取openid | |
String code=(String) request.getParameter("code"); | |
System.out.println(" code 是 "+code); | |
if(code==null){ | |
return "redirect:ErrorPageInWechatLogin.html"; | |
} | |
Request wxRequest = new Request.Builder() | |
.url(String.format("https://api.weixin.qq.com/sns/oauth2/access_token?appid=%s&secret=%s&code=%s&grant_type=authorization_code", appid,secret,code)) | |
.get() | |
.build(); | |
Response response = httpClient.newCall(wxRequest).execute(); | |
if (response.isSuccessful()){ | |
String respText = response.body().string(); | |
JSONObject json = JSONObject.parseObject(respText); | |
openid = json.getString("openid"); | |
return ("redirect:"+runDomain+"/wx.html?openid="+ openid); | |
}else { | |
return ("redirect:"+runDomain+"/wx.html?openid=获取id失败"); | |
} | |
} | |
// 获取jssdk 认证所需 appid,timestamp,noncestr,signature等信息,需要后端小伙伴配合 | |
@RequestMapping(value = "/user/wx/jssdk",method = RequestMethod.POST) | |
@ResponseBody | |
public ResJson registerJsSdk(@RequestParam("url") String url){ | |
JsApiRegistResJson json = getJsApiRegist(url); | |
if (json == null){ | |
return ResJson.failJson(-1, "获取失败", null); | |
} | |
return ResJson.successJson("获取成功", json); | |
} | |
private class JsTicket { | |
String ticket; | |
Long createTime; | |
} | |
// 应该写在Server 里面的获取 Js ticket 的 | |
// private HashMap<String, JsTicket> jsTicketMap = new HashMap<>(); | |
// 获取 JsTicket,每个 url 对应的每个 ticket 有 7200s 的有效时间 | |
// private Long lastGetTime=0L; | |
private String jsTicket = null; | |
private Long lastGetTime=0L; | |
private String accessToken = null; | |
public class JsApiRegistResJson { | |
private String appid; | |
private String timeStamp; | |
private String nonceStr; | |
private String signature; | |
public String getAppid() { | |
return appid; | |
} | |
public void setAppid(String appid) { | |
this.appid = appid; | |
} | |
public String getTimeStamp() { | |
return timeStamp; | |
} | |
public void setTimeStamp(String timeStamp) { | |
this.timeStamp = timeStamp; | |
} | |
public String getNonceStr() { | |
return nonceStr; | |
} | |
public void setNonceStr(String nonceStr) { | |
this.nonceStr = nonceStr; | |
} | |
public String getSignature() { | |
return signature; | |
} | |
public void setSignature(String signature) { | |
this.signature = signature; | |
} | |
} | |
public JsApiRegistResJson getJsApiRegist(String url){ | |
String jsTicket = getJsTicket(); | |
if (jsTicket == null){ | |
return null; | |
} | |
String timeStamp = (""+System.currentTimeMillis()).substring(0,10); | |
String nonceStr = System.currentTimeMillis()+"Test"; | |
String signature = SHA1.encode( | |
"jsapi_ticket="+jsTicket+ | |
"&noncestr="+nonceStr + | |
"×tamp="+timeStamp + | |
"&url="+url | |
); | |
JsApiRegistResJson json = new JsApiRegistResJson(); | |
json.appid = appid; | |
json.timeStamp = timeStamp; | |
json.nonceStr = nonceStr; | |
json.signature = signature; | |
return json; | |
} | |
// 获取 jsTicket(避免过时) | |
private String getJsTicket(){ | |
if (jsTicket == null){ | |
jsTicket = refreshJsTicket(); | |
lastGetTime = System.currentTimeMillis(); | |
}else { | |
if ((System.currentTimeMillis() - lastGetTime) > 1000 * 7200){ | |
jsTicket = refreshJsTicket(); | |
lastGetTime = System.currentTimeMillis(); | |
} | |
} | |
return jsTicket; | |
} | |
// 刷新 JsTicket | |
private String refreshJsTicket(){ | |
if (accessToken == null){ | |
accessToken = getAccessToken(); | |
} | |
Request request = new Request.Builder() | |
.get() | |
.url("https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token="+accessToken+"&type=jsapi") | |
.build(); | |
try { | |
Response response = httpClient.newCall(request).execute(); | |
if (response.isSuccessful()) { | |
JSONObject json = JSONObject.parseObject(response.body().string()); | |
String ticketTemp = json.getString("ticket"); | |
if (ticketTemp != null){ | |
System.out.println("刷新 jsTicket 成功" + ticketTemp); | |
return ticketTemp; | |
}else { | |
return null; | |
} | |
}else { | |
return null; | |
} | |
} catch (IOException e) { | |
e.printStackTrace(); | |
return null; | |
} | |
} | |
// 获取 AccessToken | |
private String getAccessToken(){ | |
Request request = new Request.Builder() | |
.get() | |
.url("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid="+appid+"&secret="+secret) | |
.build(); | |
try { | |
Response response = httpClient.newCall(request).execute(); | |
if (response.isSuccessful()){ | |
JSONObject json = JSONObject.parseObject(response.body().string()); | |
String accessToken; | |
if ((accessToken = json.getString("access_token") )!= null){ | |
System.out.println("获取 accessToken 成功" + accessToken); | |
return accessToken; | |
}else { | |
return null; | |
} | |
}else { | |
return null; | |
} | |
} catch (IOException e) { | |
e.printStackTrace(); | |
return null; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment