由于不同的第三方平台的授权方式不同,包括授权的端点、授权的参数等等,因此,下面我们提供了分别用于QQ、微信、钉钉OAuth 2.0的前端和后端代码。
首先是QQ OAuth 2.0的前端代码,它使用QQ提供的connect.qq.com
授权端点进行授权,并处理授权的回调:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>QQ OAuth 2.0</title>
</head>
<body>
<h1>QQ OAuth 2.0</h1>
<script src="https://open.mobile.qq.com/sdk/qqapi.js?_bid=152"></script>
<script>
var appId = 'YOUR_APP_ID_HERE',
redirectUri = encodeURIComponent('http://localhost:8080/oauth/callback/qq'),
scope = 'get_user_info';
qq.login(function(res) {
if (res.errMsg == 'login:ok') {
var access_token = res.access_token,
expires_in = res.expires_in,
openid = res.openid;
// Send OAuth login data to server-side
var xhr = new XMLHttpRequest();
xhr.open('POST', 'http://localhost:8080/oauth2/callback', true);
xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
xhr.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
// Handle successful login
window.location.href = "/";
}
};
xhr.send('provider=qq&access_token=' + access_token + '&expires_in=' + expires_in + '&openid=' + openid);
}
}, {
clientId: appId,
scope: scope,
redirectURI: redirectUri
});
</script>
</body>
</html>
接下来是QQ OAuth 2.0的后端代码,它将处理来自QQ的OAuth回调,并从回调中提取访问令牌等数据:
import java.io.IOException;
import java.util.Properties;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.message.BasicNameValuePair;
import org.json.JSONException;
import org.json.JSONObject;
public class QQOAuth2CallbackServlet extends HttpServlet {
private static final String CALLBACK_PATH = "/oauth/callback/qq";
private static final String AUTHORIZATION_ENDPOINT = "https://graph.qq.com/oauth2.0/authorize";
private static final String TOKEN_ENDPOINT = "https://graph.qq.com/oauth2.0/token";
private static final String USERINFO_ENDPOINT = "https://graph.qq.com/user/get_user_info";
private static final String APP_ID = "YOUR_APP_ID_HERE";
private static final String APP_KEY = "YOUR_APP_KEY_HERE";
private static final String REDIRECT_URI = "http://localhost:8080/oauth/callback/qq";
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String code = req.getParameter("code");
String state = req.getParameter("state");
String access_token = "";
String openid = "";
String token_url = TOKEN_ENDPOINT + "?grant_type=authorization_code&client_id="
+ APP_ID + "&client_secret=" + APP_KEY + "&code=" + code + "&redirect_uri="
+ REDIRECT_URI;
CloseableHttpClient httpclient = HttpClientBuilder.create().build();
HttpPost httpPost = new HttpPost(token_url);
HttpResponse response = httpclient.execute(httpPost);
HttpEntity entity = response.getEntity();
if (entity != null) {
String content = EntityUtils.toString(entity);
String[] items = content.split("&");
for (String item : items) {
if (item.startsWith("access_token=")) {
access_token = item.substring(13);
} else if (item.startsWith("expires_in=")) {
// 这个令牌将在多少秒后过期
int expiresIn = Integer.parseInt(item.substring(11));
} else if (item.startsWith("refresh_token=")) {
// 如果支持刷新令牌,那么这里将包含一个用于获取新访问令牌的令牌
String refresh_token = item.substring(14);
}
}
}
// 使用令牌请求QQ的OpenID
CloseableHttpClient httpclient2 = HttpClientBuilder.create().build();
HttpPost httpPost2 = new HttpPost(
"https://graph.qq.com/oauth2.0/me?access_token=" + access_token);
HttpResponse response2 = httpclient2.execute(httpPost2);
HttpEntity entity2 = response2.getEntity();
if (entity2 != null) {
String content = EntityUtils.toString(entity2);
content = content.replace("callback( ", "");
content = content.replace(" );", "");
JSONObject json = new JSONObject(content);
openid = json.getString("openid");
}
// 使用QQ的 openid 获取用户信息
CloseableHttpClient httpclient3 = HttpClientBuilder.create().build();
HttpPost httpPost3 = new HttpPost(USERINFO_ENDPOINT + "?access_token=" + access_token
+ "&oauth_consumer_key=" + APP_ID + "&openid=" + openid);
HttpResponse response3 = httpclient3.execute(httpPost3);
HttpEntity entity3 = response3.getEntity();
if (entity3 != null) {
String content = EntityUtils.toString(entity3);
JSONObject json = new JSONObject(content);
String nickname = json.getString("nickname");
String gender = json.getString("gender");
String avatar = json.getString("figureurl_qq_2");
int province = json.getInt("province");
int city = json.getInt("city");
// do something with user info
}
// redirect user to homepage after successful authentication
resp.sendRedirect("/");
}
}
下面是微信OAuth 2.0的前端代码,它使用微信提供的open.weixin.qq.com
授权端点进行授权,并处理授权的回调:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>WeChat OAuth 2.0</title>
</head>
<body>
<h1>WeChat OAuth 2.0</h1>
<script src="//res.wx.qq.com/connect/sdk/jsfile/sdk/versions/version1.6.0/mmversion.js"></script>
<script>
var appId = 'YOUR_APP_ID_HERE',
redirectUri = encodeURIComponent('http://localhost:8080/oauth/callback/weixin'),
scope = 'snsapi_login';
document.addEventListener("WeixinJSBridgeReady", function () {
WeixinJSBridge.invoke('getLoginStatus', {}, function (res) {
if (res.err_msg == "login:ok") {
var code = res.code;
// Send OAuth login data to server-side
var xhr = new XMLHttpRequest();
xhr.open('POST', 'http://localhost:8080/oauth2/callback', true);
xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
xhr.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
// Handle successful login
window.location.href = "/";
}
};
xhr.send('provider=weixin&code=' + code);
} else {
WeixinJSBridge.invoke('authorize', {
scope: scope,
state: 'wx_login'
}, function(res) {});
}
});
}, false);
</script>
</body