本文采用授權(quán)碼模式,參考https://www.cnblogs.com/y-yxh/p/5903771.html
總結(jié)起來就三點(diǎn):
1.請求fb的認(rèn)證url沐旨,fb會(huì)根據(jù)瀏覽器是否已登錄而判斷是否重定向到登陸頁面琴昆,然后以u(píng)rl參數(shù)形式返回code到你提交的回調(diào)地址酬土。
如何請求败潦?下面是一個(gè)例子管行。
"https://www.facebook.com/dialog/oauth?" +
"client_id=595xxxxxxx711&" +
"redirect_uri=http://localhost:9000/fb/auth&" + //這是在fb app上定義的回調(diào)地址厨埋,要與后臺(tái)方法一致
"scope=public_profile,user_birthday,email&state=xxxx" //如果需要的話,可以在state上加上參數(shù)(比如加上頁面id等判斷該請求從何頁面而來)
2.拿著返回來的code捐顷,再次請求fb的tokenurl用以交換token荡陷,最后同樣返回access_token到上文的回調(diào)url
"https://graph.facebook.com/oauth/access_token?"+
"client_id=xxx"+
"client_secret=xxx"+
"redirect_uri=xxx"+
"code=xxx"
//這一步需要四個(gè)參數(shù),前兩個(gè)在fb app上迅涮,redirect_uri同上废赞,code是上步拿到的
3.(非必須) 用第2步拿到的access_token請求用戶信息,姓名email等等叮姑。不過既然都第三方認(rèn)證了蛹头,目的基本都是為了用戶信息。
"https://graph.facebook.com/me"
下面上代碼:
def fbAuth() = Action { request =>
//不需要的話就不用附帶state參數(shù)請求
val stateStr = request.getQueryString("state").getOrElse(throw new MsgException(""))
//回調(diào)地址戏溺,即本方法的url
val selfUri = "http://" + request.host + request.path
request.getQueryString("code") match {
case Some(code) =>
//第二次請求
val f = ws.url(fb.tokenUrl).addQueryStringParameters( //ws是play.api.libs.ws.WSClient
"client_id" -> fb.clientId,
"redirect_uri" -> selfUri,
"client_secret" -> fb.clientSecret,
"code" -> code
).get().flatMap { response =>
if (response.status == 200) {
(response.json \ "access_token").asOpt[String] match {
case Some(token) =>
ws.url(fb.getInfoUrl).addQueryStringParameters( //第三步請求用戶信息
"fields" -> fb.getInfoFields,
"access_token" -> token
).get().map { userInfo =>
if (userInfo.status == 200) {
Ok(userInfo.json)
} else {
BadRequest(userInfo.json)
}
}
case _ => Future(Unauthorized)
}
} else {
Future(BadRequest)
}
}
val result = Await.result(f, Duration.Inf)
result
case _ => //第一次請求
Redirect(
s"${fb.requestUrl}?client_id=${fb.clientId}&redirect_uri=$selfUri&scope=${fb.requestScope}&state=$stateStr"
)
}
}
fb.tokenUrl等等部分我寫在了application.conf里渣蜗,如下
fb {
clientId="5xxxxx1"
clientSecret="7xxxxxxx2"
requestUrl="https://www.facebook.com/dialog/oauth"
requestScope="public_profile,user_birthday,email"
tokenUrl="https://graph.facebook.com/oauth/access_token"
#https://graph.facebook.com/me?fields=id,picture,name,birthday,email&access_token=xxx
getInfoUrl="https://graph.facebook.com/me"
getInfoFields="id,picture,name,birthday,email"
}
最后在頁面上會(huì)打印出請求到的用戶信息。
另外也可以把第一步的請求url寫道html的a標(biāo)簽里旷祸「剑考慮到會(huì)暴露client_id以及移植的方便性,未作此處理托享。當(dāng)然fb文檔里也有純前端js方法實(shí)現(xiàn)的認(rèn)證骚烧,由于安全性原因也未采用。