[Grails]整合Facebook登入機制oAuth

先前介紹了很多Spring Security Core Plugin的用法,在Spring Security Core Plugin的頁面中有提到相當多的Plugin是架構在Spring Security基礎上的,包括Facebook、Twitter、OpenID等。這篇文章將更進階的將Facebook登入與Spring Security Core機制做一個整合。

其實如果網站單純要用某個oAuth的認證方式的話,建議是直接可以參考官方的API直接開發就可以,但是如果跟我一樣需要兼容Spring Security來做登入與頁面權限的管理,用人家開發好的Plugin真的省事很多。

這個套件目前算是還有在更新,不過不知道為什麼評價不是很高,至少有達到我基本的要求就好,細部的不方便就不管了。

在使用這個套件前,務必先安裝好Spring Security Core Plugin,可以參考之前的文章:Grails+Spring Security Core Plugin(Part1) ,裝好以後要做到產生SysUser/SysRole的步驟。

#01#安裝套件
在BuildConfig.groovy裡面加上以下這段

plugins {
        compile “org.grails.plugins:spring-security-facebook:0.11″
}

//說明裡面是0.11版本,但是實際上是0.14.2,我還是用0.11來做

#02#設定Facebook App
https://developers.facebook.com/新增一個App(應用程式)
輸入方便識別的應用程式名稱以及小寫英文的程式名稱空間

選擇以 [Facebook 登入網站]這個項目,設定網站位址

(如果你是在本機開發,可能只有localhost,但是FB並不接受localhost or 127.0.0.1,所以還是要用一個domain name,如果沒有的話隨便設定一個,然後去改你本機的hosts設定,參考這裡)

如果設定完成後,你就可以看到你接下來需要用到的App ID跟App Secret

#03#新增FacebookUser
需要新增一個FacebookUser來儲存該FB的ID與aceesToken,並且跟現有的SpringSecurity User做關連,這裡我以xervice.Member來做例子。

long uid

String accessToken
Date accessTokenExpires
static belongsTo = [user: SysUser]

以上四個屬性是必要的,其中static belongsTo = [user: SysUser]中的SysUser則需看你的SpringSecurity 設定而決定。

class Member {

/* Default (injected) attributes of GORM */

String aboutMe
Date birthday
boolean gender
String email
boolean emailConfirm
String firstName
String lastName
long uid
String accessToken
Date accessTokenExpires
static belongsTo = [user: SysUser]


    static mapping = {
autoTimestamp true
aboutMe type: ‘text’
    }
    
static constraints = {
email (email: true,nullable:true,blank:true)
firstName(blank: true,nullable: true)
lastName(blank: true,nullable: true)
aboutMe(blank: true,nullable: true)
birthday(nullable: true)
uid(unique: true)
    }

}

#04#設定Facebook Plugin
網站上面是建議直接打grails s2-init-facebook //configure Spring Security Facebook
但是好像有點問題,其實直接去改Config.groovy就可以

grails.plugins.springsecurity.facebook.domain.classname=’xervice.Member’
grails.plugins.springsecurity.facebook.appId=’你的APP ID’
grails.plugins.springsecurity.facebook.secret=’你的APP Secret’

#05#設定登入/登出按鈕

因為這個plugin預設幫你新增一個Spring Security User做關連,同時assign ROLE_USER與ROLE_FACEBOOK,因此可以結合Spring Security 的TagLib來做登入登出機制的判斷。
<sec:ifNotGranted roles="ROLE_USER">
  <facebookAuth:connect />
</sec:ifNotGranted>
<sec:ifAllGranted roles="ROLE_USER">
  Welcome <sec:username/>! (<g:link uri="/j_spring_security_logout">Logout</g:link>)
</sec:ifAllGranted>

如此一來就大功告成了,不過離實際的需求可能還是有點出入,還好這個plugin保留不少客製化的空間可以修改。

#06#客製化-設定存取其他資料
這個plugin預設只會去存取該使用者在Facebook的user id,如果需要存取其他資料,則需要在Config.groovy設定

grails.plugins.springsecurity.facebook.permissions = ’email,user_about_me,user_birthday’

其他設定可以參考這裡
https://developers.facebook.com/docs/reference/login/#permissions
http://splix.github.io/grails-spring-security-facebook/guide/single.html#3.1%20Basic%20Usage

#07#客製化-使用FacebookAuthService
這個plugin預設是會在第一次登入時,建立一個SysUser(Spring Security User),然後把username設定為"facebook_xxxxxxx" xxxxxx代表facebook user id,同時assign ROLE_USER與ROLE_FACEBOOK,最後再建立一個Member(FacebookUser),預設寫入uid(=facebook user id)、accessToken與accessTokenExpires

我這裡的作法會示範透過API取得該User在Facebook上的email,並且以email當做SysUser.username,並設定Member.email

步驟如下:
在src/groovy新增一個FacebookAuthService.groovy
我這裡改寫afterCreate的method,也就是當使用者第一次登入,並且已經新增完SysUser與Member後,才會執行的method。

class FacebookAuthService {

    static transactional = true
def grailsApplication
    void afterCreate(itri.Member user, FacebookAuthToken token){
def appid = grailsApplication.config.grails.plugins.springsecurity.facebook.appId;
def secret = grailsApplication.config.grails.plugins.springsecurity.facebook.secret;


def url = “https://graph.facebook.com/me?access_token="+user.accessToken; 

def result = [:]
try {
def conn = url.openConnection()
conn.doOutput = true
conn.doInput = true

def paramString = “access_token="+user.accessToken; 

conn.outputStream << paramString
result = JSON.parse(conn.inputStream.text)
} catch (Exception ex) {
ex.printStackTrace()
}

if(result.email){
user.email = result.email

user.user.username = result.email
user.user.save(flush: true)
}

}
}

大功告成!!!

其他還有很多可以改寫的Method,可以參考官方說明文件

在Discuz文章內加上社群分享按鈕

要在Discuz的文章上面加上如Facebook like(讚)、Google+ +1按鈕時,必須要去修改它的template file。

在此之前先決定你要放上哪些按鈕

Facebook like的官方產生器
Google+ +1按鈕的官方產生器
AddThis一次產生Facebook、Twitter與Pinterest分享,還有其他書籤服務按鈕

透過以上服務產生你的程式碼,之後只要找到對應的位置貼上就可以了

我這裡的作法是貼在文章的第一行,步驟如下:

  1. 開啟templatedefaultforumviewthread_node.htm
  2. 找到<div class="pct">這行
  3. 在<div class="pct">後面貼上你獲得的程式碼

效果可以參考這裡 http://urstock.net/forum/forum.php?mod=viewthread&tid=2526&extra=page%3D1