2015年2月10日火曜日

fuelphp+Facebook SDK for PHP v4+App Roleでサイト管理画面を楽に作る方法的なお話

  • このエントリーをはてなブックマークに追加

新しくサービスを作るなりなんなりするときにやっぱり作る必要がある管理画面。
fuelphpのmigrationなりを使えばさくっと作れるんだけど、そこで権限の付与とかなるとconfigの設定なりで面倒だったり。
というかそんなのはもっと簡単にやりたいぞ!っていう人にオススメなのがFacebookのログイン機能を使う的な。

Facebookのアプリにはサンドボックスモードがあるので誰もがアプリを使う事が出来ないようにするとか、
Roleという形で役割を付与する事が出来たりする。
で、これを使えばサイトの管理画面でもその権限を継承したままアプリをインストールした人しか見れないので楽だったり。

ということで今日はアプリの権限を確認する方法だったり、管理画面の認証機能だったりの作り方のお話をば。

■1. Facebookアプリの作成
developers.facebook.comにアクセスして、アプリの作成。
・サンドボックスモードにする
・Roleで適当に色んな人を追加する

■2. fuelphpでFacebook SDK for PHP v4をvendorに入れる
こちらにさくっと方法を書いてあるので要参照

■3. 基底コントローラーの作成

class Controller_Base extends Controller_Template{
  public $template = 'base-template';

  public function before(){
    parent::before();

    if(!Session::get("fbsession",null)){
      Response::redirect("/login");
    }
    else{
      $user = Session::get("user");
      $fbsession = Session::get("fbsession");
      
      Session::set("user",$user);
      Session::set("fbsession",$fbsession);
    }
  }

  public function after($response){
    $response = parent::after($response);

    return $response;
  }
}
base.phpみたいな名前にしておいて、このコントローラーを常にextendsするようにする。
そうすればfbsessionというloginコントローラーで付与されるセッションがなければ/loginにリダイレクトするって形になる。
ちなみにloginコントローラーはbaseコントローラーをextendsする必要はない。

■4. ログインコントローラーの作成
use Facebook\FacebookSession;
use Facebook\FacebookRequest;
use Facebook\FacebookResponse;
use Facebook\FacebookRedirectLoginHelper;
use Facebook\GraphUser;
use Facebook\FacebookSDKException;
use Facebook\FacebookRequestException;
use Facebook\FacebookAuthorizationException;

class Controller_Login extends Controller{
  public function before(){
    if(Session::get("fbsession",null)){
      Response::redirect("/");
    }
  }

  public function action_index(){
    session_start();
    FacebookSession::setDefaultApplication('facebook_app_id','facebook_app_secret');

    $helper = new FacebookRedirectLoginHelper('http://hogehoge/login/callback');

    $view = View::forge('login/index');
    $view->loginUrl = $helper->getLoginUrl();

    return $view;
  }

  // callback
  public function action_callback(){
    session_start();
    FacebookSession::setDefaultApplication('facebook_app_id','facebook_app_secret');

    $helper = new FacebookRedirectLoginHelper('http://hogehoge/login/callback');

    // get user data
    try{
      $session = $helper->getSessionFromRedirect();

      if(!isset($session)){
        Response::redirect($helper->getLoginUrl());
      }

      Session::set("fbsession",$session);

      $request = new FacebookRequest($session,'GET',"/me");
      $response = $request->execute();
      $me = $response->getGraphObject(GraphUser::className())->asArray();

      Session::set("user",array(
        "uid" => $me['id'],
        "username" => $me['name'],
        "img" => "https://graph.facebook.com/{$me['id']}/picture?type=large"
      ));
    }
    catch(FacebookRequestException $ex){
      // error
    }
    catch(\Exception $ex){
      // error
    }

    // check user permission
    if(isset($session)){
      $appToken = file_get_contents("https://graph.facebook.com/oauth/access_token?client_id=".'facebook_app_id'."&client_secret=".'facebook_app_secret'."&grant_type=client_credentials");
      $appToken = preg_replace("/.+\|/","",$appToken);

      $session = new FacebookSession($appToken);
      $session = FacebookSession::newAppSession();

      try{
        $request = new FacebookRequest($session,'GET',"/".Config::get("facebook.init.appId")."/roles");
        $response = $request->execute();
        $graphObject = $response->getGraphObject(GraphUser::className())->asArray();

        foreach($graphObject['data'] as $data){
          if($data->user === Session::get("user.uid")){
            $user = Session::get("user");

            // set user permission
            switch($data->role){
              case "administrators":
                $user['admin'] = 1;
                $user['developer'] = 1;
                $user['test'] = 1;
                $user['insight'] = 1;
                break;
              case "developers":
                $user['admin'] = 0;
                $user['developer'] = 1;
                $user['test'] = 1;
                $user['insight'] = 1;
                break;
              case "testers":
                $user['admin'] = 0;
                $user['developer'] = 0;
                $user['test'] = 1;
                $user['insight'] = 1;
                break;
              case "insights users":
                $user['admin'] = 0;
                $user['developer'] = 0;
                $user['test'] = 0;
                $user['insight'] = 1;
                break;
              default:
                $user['admin'] = 0;
                $user['developer'] = 0;
                $user['test'] = 0;
                $user['insight'] = 0;
                break;
            }

            Session::set("user",$user);
          }
        }

        Response::redirect("/");
      }
      catch(FacebookRequestException $ex){
        // error
      }
    }
    else{
      $loginUrl = $helper->getLoginUrl();
      Response::redirect($loginUrl);
    }
  }
}
ってな感じのログインコントローラーを用意してあげればいい。
かなり長いけどこんな感じでOK。
callbackの最初の部分でユーザー情報取得、途中からfacebookアプリの権限を持っているか確認して、
持ってたらfacebookアプリの権限に応じて4種類の権限をするという感じ。

なのでアクセス出来ないようにしたい場合は、facebookアプリの権限からユーザーを消せば大丈夫
サンドボックスモードなのでそもそもRoleに入っているユーザーでないとアプリにアクセスできないわけだし。

ってな感じで作ってあげたbaseコントローラーを継承しつつ、
セッションが無かったらloginコントーラーに飛ばすってことでクローズドで、
各ユーザーの権限を簡単に変更する事が出来る管理画面の作成が出来るみたいな。

Adsense