微信三方登錄實現原理準備工作
準備工作
網站應用微信登錄是基於OAuth2.0協議標準構建的微信OAuth2.0授權登錄系統。
在進行微信OAuth2.在進行微信OAuth2.0授權登錄接入之前,在微信開放平臺註冊開發者帳號,並擁有一個已審覈通過的網站應用,並獲得相應的AppID和AppSecret,申請微信登錄且通過審覈後,可開始接入流程。
授權流程說明
微信OAuth2.0授權登錄讓微信用戶使用微信身份安全登錄第三方應用或網站,在微信用戶授權登錄已接入微信OAuth2.0的第三方應用後,第三方可以獲取到用戶的接口調用憑證(access_token),通過access_token可以進行微信開放平臺授權關係接口調用,從而可實現獲取微信用戶基本開放信息和幫助用戶實現基礎開放功能等。
微信OAuth2.0授權登錄目前支持authorization_code模式,適用於擁有server端的應用授權。該模式整體流程爲:
- 第三方發起微信授權登錄請求,微信用戶允許授權第三方應用後,微信會拉起應用或重定向到第三方網站,並且帶上授權臨時票據code參數;
- 通過code參數加上AppID和AppSecret等,通過API換取access_token;
- 通過access_token進行接口調用,獲取用戶基本數據資源或幫助用戶實現基本操作。
第一步:請求CODE
第三方使用網站應用授權登錄前請注意已獲取相應網頁授權作用域(scope=snsapi_login),則可以通過在PC端打開以下鏈接:
https://open.weixin.qq.com/connect/qrconnect?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect
若提示“該鏈接無法訪問”,請檢查參數是否填寫錯誤,如redirect_uri的域名與審覈時填寫的授權域名不一致或scope不爲snsapi_login。
參數說明
參數 是否必須 說明
appid 是 應用唯一標識
redirect_uri 是 請使用urlEncode對鏈接進行處理
response_type 是 填code
scope 是 應用授權作用域,擁有多個作用域用逗號(,)分隔,網頁應用目前僅填寫snsapi_login即
state 否 用於保持請求和回調的狀態,授權請求後原樣帶回給第三方。該參數可用於防止csrf攻擊(跨站請求僞造攻擊),建議第三方帶上該參數,可設置爲簡單的隨機數加session進行校驗
返回說明
用戶允許授權後,將會重定向到redirect_uri的網址上,並且帶上code和state參數
redirect_uri?code=CODE&state=STATE
若用戶禁止授權,則重定向後不會帶上code參數,僅會帶上state參數
redirect_uri?state=STATE
代碼如下:
@RequestMapping(value = "/wxLoginPage")
public String wxKfLoginPage(HttpServletRequest request) throws Exception {
// 防止csrf攻擊(跨站請求僞造攻擊)
String state = UUID.randomUUID().toString().replaceAll("-", "");
HttpSession session = request.getSession();
//存入session
session.setAttribute("wechat-kf-state",state);
//普通微信三方地址
String url = "https://open.weixin.qq.com/connect/qrconnect?" +
"appid="+constants.getWeCatKfAppId() +
"&redirect_uri="+constants.getWeCatKfRedirectUrl()+
"&response_type=code" +
"&scope=snsapi_login" +
"&state="+state+
"#wechat_redirect";
return "redirect:"+url;
}
第二步:執行成功後會執行第一步的回調方法
@RequestMapping("/callBack")
public String callBack(HttpServletRequest request){
//得到code用於交換token
String code = request.getParameter("code");
String state = request.getParameter("state");
//判斷state是否合法
String stateStr = (String)request.getSession().getAttribute("wechat-kf-state");
if(StringUtils.isEmpty(code)||StringUtils.isEmpty(state)||!state.equals(stateStr)){
request.setAttribute("msg","非法操作,請重新登錄!");
return "userInfo";
}
//用戶授權後的code換取token
Map token = wechatService.getAccessToken(code,constants.getWeCatKfAppId(),constants.getWeCatKfAppSecret());
//判斷是否成功獲取到了token
if(token.get("errcode")!=null){
request.setAttribute("msg","token獲取失敗,請重新登錄");
return "userInfo";
}
if(StringUtils.isEmpty((String)token.get("access_token"))||StringUtils.isEmpty((String)token.get("openid"))){
request.setAttribute("msg","access_token拉取失敗,請重新登錄");
return "userInfo";
}
//刷新accesstoken
Map refreshToken = wechatService.refrehToken(constants.getWeCatKfAppId(), (String) token.get("refresh_token"));
//使用token交換獲取用戶信息
WxchatUser user = wechatService.getUserInfo(refreshToken);
//將用戶信息入棧
request.setAttribute("user",user);
return "userInfo";
}
第三步:在回調方法中的通過code換取accesstoken、
/**
* 通過code獲取token
* @return
*/
public Map getAccessToken(String code,String appid,String secret){
//構建請求數據
String urlToken = "https://api.weixin.qq.com/sns/oauth2/access_token";
Map t = new HashMap();
t.put("appid",appid);
t.put("secret",secret);
t.put("code",code);
t.put("grant_type","authorization_code");
//調用httpclient處理請求得到返回json數據
String returnJson = HttpClientUtil.doGet(urlToken, t);
Map token = (Map) JSONObject.parse(returnJson);
return token;
}
第四步:通過accesstoken和openid獲取用戶信息
/**
* 通過token獲取用戶信息
* @param token
* @return
*/
public WxchatUser getUserInfo(Map token){
String urlUser = "https://api.weixin.qq.com/sns/userinfo";
//構建請求數據
Map u = new HashMap();
u.put("access_token",token.get("access_token"));
u.put("openid",token.get("openid"));
u.put("lang","zh_CN");
//調用httpclient處理請求得到用戶信息json數據
String user = HttpClientUtil.doGet(urlUser, u);
//轉換成用戶對象
WxchatUser wxchatUser = JSONObject.parseObject(user, WxchatUser.class);
return wxchatUser;
}
第五步:刷新token(可省略這步)
/**
* 刷新token處理
* @return
*/
public Map refrehToken(String appid,String refresh_token){
String urlRefresh = "https://api.weixin.qq.com/sns/oauth2/refresh_token";
//構建請求參數
Map m = new HashMap();
m.put("appid",appid);
m.put("grant_type","refresh_token");
m.put("refresh_token",refresh_token);
//調用httpclient發出請求
Map refreshToken = (Map)JSONObject.parse(HttpClientUtil.doGet(urlRefresh, m));
return refreshToken;
}
通過以上步驟即可實現微信三方授權登錄。如有疑問歡迎留言。