案例1 - signInWithTwitch 以 Twitch 登入,以 Parse + Oauth.io 為例
我們要有使用者的 Twitch 授權,並幫使用者建立帳號。
所以委託 oauth.io 取得 Twitch 授權,請 Parse 與 Twitch 驗證授權是否合法後,建立 Parse 帳號換證。
<script src="//code.jquery.com/jquery-1.11.3.min.js"></script>
<script src="//code.jquery.com/jquery-migrate-1.2.1.min.js"></script>
<script src="oauth.min.js"></script>
<!-- https://parse.com/docs/downloads -->
<script src="//parse.com/downloads/javascript/parse/latest/min.js"></script>
<script>
Parse.initialize("{parse_app_id}", "{parse_js_key}");
$(document).ready(function() {
$("#login").click(function(event) {
OAuth.initialize('{oauth_app_id}')
OAuth.redirect('twitch', "https://yongjhih.github.io/");
});
// ...
OAuth.callback('twitch').done(function(result) {
console.log(result);
Parse.Cloud.run("signInWithTwitch", access_token).then(function(sessionToken) {
console.log(sessionToken);
return Parse.User.become(sessionToken);
}, function(e) {
console.log(e);
});
}).fail(function(e) {
console.log(e);
});
});
</script>
cloud/twitch.js:
var Parse = require('parse-cloud-express').Parse;
function s4() {
return Math.floor((1 + Math.random()) * 0x10000).toString(16).substring(1);
}
function guid() {
return s4() + s4() + '-' + s4() + '-' + s4() + '-' +
s4() + '-' + s4() + s4() + s4();
}
function guid20() {
return s4() + s4() + s4() + s4() + s4();
}
/**
* Returns twitchUser
*
* @param {String} token
* @returns {Promise<TwitchUser>} twitchUser
* @see https://github.com/justintv/twitch-api
* @see https://github.com/justintv/Twitch-API/blob/master/authentication.md#scope
*/
function getTwitchUser(accessToken) {
return Parse.Cloud.httpRequest({
url: "https://api.twitch.tv/kraken/user",
params: {
oauth_token: accessToken
}
}).then(function(httpResponse) {
return JSON.parse(httpResponse.text);
});
}
/**
* Returns email
*
* @param {String} token
* @returns {Promise<String>} email
*/
function getEmail(accessToken) {
return getTwitchUser(accessToken).then(function(twitchUser) {
return twitchUser.email; // { email: "[email protected]" }
});
}
/**
* Returns the session token of available parse user via twitch access token within `request.params.accessToken`.
*
* @param {Object} request Require request.params.accessToken
* @param {Object} response
* @returns {String} sessionToken
*/
function signInWithTwitch(request, response) {
promiseResponse(signInWithTwitchPromise(request.user, request.params.accessToken, request.params.expiresTime), response);
}
/**
* Returns the session token of available parse user via twitch access token.
*
* @param {Parse.User} user
* @param {String} accessToken
* @param {Number} expiresTime
* @returns {Promise<String>} sessionToken
*/
function signInWithTwitchPromise(user, accessToken, expiresTime) {
Parse.Cloud.useMasterKey();
var userPromise;
if (user) { // login
userPromise = Parse.Promise.as(user);
} else { // not login
if (!accessToken) {
return Parse.Promise.error("Require accessToken parameter");
}
userPromise = getTwitchUser(accessToken).then(function(twitchUser) {
if (!twitchUser) return Parse.Promise.error("Invalid token");
var userQuery = new Parse.Query(Parse.User);
userQuery.equalTo("email", twitchUser.email);
userQuery.equalTo("username", twitchUser.name);
return userQuery.first().then(function(user) {
if (user) return Parse.Promise.as(user);
var newUser = new Parse.User();
var username = twitchUser.name;
var password = "twitch" + guid20();
newUser.setUsername(username); // assert username not duplicated
newUser.setPassword(password);
newUser.setEmail(twitchUser.email);
var attrs = {
// exception: {"code":251,"message":"custom credential verification for auth service twitch failed"}
//"authData": {
// "twitch": {
// "id": twitchUser._id,
// "access_token": accessToken,
// "expires_time": expiresTime
// }
//},
uid: twitchUser._id.toString()
};
return newUser.signUp(attrs);
});
});
}
return userPromise.then(function(user) {
return user.fetch();
}).then(function(user) {
if (user) {
return Parse.Promise.as(user._sessionToken); // getSessionToken()?
} else {
return Parse.Promise.error("Twitch user not found");
}
});
};
/**
* @param {Function(request, response)} func
*/
function defineParseCloud(func) {
Parse.Cloud.define(func.name, func);
}
function promiseResponse(promise, response) {
promise.then(function(o) {
response.success(o);
}, function(error) {
response.error(error);
})
}
defineParseCloud(signInWithTwitch);
https://api.twitch.tv/kraken/user?oauth_token={token}
{
"display_name": "yongjhih",
"_id": 35947509,
"name": "yongjhih",
"type": "user",
"bio": null,
"created_at": "2012-09-04T01:50:36Z",
"updated_at": "2015-10-19T08:48:00Z",
"logo": "http://static-cdn.jtvnw.net/jtv_user_pictures/yongjhih-profile_image-d800fd20bcb0b04f-300x300.jpeg",
"_links": {
"self": "https://api.twitch.tv/kraken/users/yongjhih"
},
"email": "[email protected]",
"partnered": false,
"notifications": {
"push": false,
"email": true
}
}