weixin_33725270 2018-08-21 17:41 采纳率: 0%
浏览 68

Firebase Auth JS / PHP

I've been tasked to build a web interface for an Android app based on firebase. I've got a handful of endpoints, that interact with the database (Cloud functions). To access those endpoints I need to authenticate an user with email and password[1], retrieve an accessToken[2] und authorize every request to the endpoints with an Authorization: Bearer {accessToken} header.

I use php and struggle to wrap my mind around how to manage authenticated user in my app.

TL;DR please see my final solution in php only. https://stackoverflow.com/a/52119600/814031

I transfer the accessToken via ajax in a php session, to sign the cURL requests to the endpoints. Apparently there is no other way around than use the firebase JS auth (not as far as I understand[4]).

My question is: Is it enough to save the accessToken in a php session and compare it with every page load via an ajax POST request (see code below)? What would be a more robust strategy to handle that in php?

Edit: A user pointed out that using classic php sessions with JWT tokens don't make much sense and I read up about that topic. So regarding Firebase - is this something to consider? https://firebase.google.com/docs/auth/admin/manage-cookies

Firebase Auth provides server-side session cookie management for traditional websites that rely on session cookies. This solution has several advantages over client-side short-lived ID tokens, which may require a redirect mechanism each time to update the session cookie on expiration:

Here is what I got:

1. Login Page

As described in the Firebase examples[3]

function initApp() {

  firebase.auth().onAuthStateChanged(function (user) {
    if (user) {
      // User is signed in.

      // obtain token, getIdToken(false) = no forced refresh
      firebase.auth().currentUser.getIdToken(false).then(function (idToken) {

        // Send token to your backend via HTTPS
        $.ajax({
          type: 'POST',
          url: '/auth/check',
          data: {'token': idToken},
          complete: function(data){
            // data = {'target' => '/redirect/to/route'}
            if(getProperty(data, 'responseJSON.target', false)){
              window.location.replace(getProperty(data, 'responseJSON.target'));
            }
          }
        });
        // ...
      }).catch(function (error) {
        console.log(error);
      });


    } else {
      // User Signed out
      $.ajax({
        type: 'POST',
        url: '/auth/logout',

        complete: function(data){
          // data = {'target' => '/redirect/to/route'}
          if(getProperty(data, 'responseJSON.target', false)){
            // don't redirect to itself
            // logout => /
            if(window.location.pathname != getProperty(data, 'responseJSON.target', false)){
              window.location.replace(getProperty(data, 'responseJSON.target'));
            }
          }
        }
      });

      // User is signed out.
    }

  });
}

window.onload = function () {
  initApp();
};

2. a php controller to handle the auth requests

public function auth($action)
{

  switch($action) {
    // auth/logout
    case 'logout':

      unset($_SESSION);
      // some http status header and mime type header
      echo json_encode(['target' => '/']); // / => index page
    break;

    case 'check':

      // login.
      if(! empty($_POST['token']) && empty($_SESSION['token'])){

        // What if I send some bogus data here? The call to the Endpoint later would fail anyway
        // But should it get so far?

        $_SESSION['token'] = $_POST['token'];

        // send a redirect target back to the JS
        echo json_encode(['target' => '/dashboard']);
        break;
      }


      if($_POST['token'] == $_SESSION['token']){
        // do nothing;
        break;
      }
    break;
  }
}

3. the Main controller

// pseudo code
class App
{
  public function __construct()
  {
    if($_SESSION['token']){
      $client = new \GuzzleHttp\Client();
      // $user now holds all custom access rights within the app.
      $this->user = $client->request(
        'GET', 
        'https://us-centralx-xyz.cloudfunctions.net/user_endpoint',
        ['headers' => 
                [
                    'Authorization' => "Bearer {$_SESSION['token']}"
                ]
            ]
        )->getBody()->getContents();
    }else{
      $this->user = null;
    }
  }

  public function dashboard(){
    if($this->user){
      var_dump($this->user);
    }else{
      unset($_SESSION);
      // redirect to '/' 
    }
  }
}

Note: I'm aware of this sdk https://github.com/kreait/firebase-php and I read a lot in the issues there and in posts here on SO, but I got confused, since there is talk about full admin rights etc. and I really only interact with the endpoints that build upon firebase (plus firebase auth and firestore). And I'm still on php 5.6 :-/

Thanks for your time!

  • 写回答

3条回答

  • weixin_33724659 2018-08-21 17:49
    关注

    You really aren't supposed to use sessions in PHP when using tokens. Tokens should be sent in the header on every request (or a cookie works too).

    Tokens work like this: 1. You sign in, the server mints a token with some information encoded 2. You send that token back on every request

    Based on the information encoded in the token, the server can get information about the user. Typically a User ID of some sort is encoded in it. The server knows it's a valid token because of the way it's encoded.

    Send the token on every request you need to make, then in PHP you can just pass that token to the other API

    评论

报告相同问题?

悬赏问题

  • ¥15 求差集那个函数有问题,有无佬可以解决
  • ¥15 【提问】基于Invest的水源涵养
  • ¥20 微信网友居然可以通过vx号找到我绑的手机号
  • ¥15 寻一个支付宝扫码远程授权登录的软件助手app
  • ¥15 解riccati方程组
  • ¥15 display:none;样式在嵌套结构中的已设置了display样式的元素上不起作用?
  • ¥15 使用rabbitMQ 消息队列作为url源进行多线程爬取时,总有几个url没有处理的问题。
  • ¥15 Ubuntu在安装序列比对软件STAR时出现报错如何解决
  • ¥50 树莓派安卓APK系统签名
  • ¥65 汇编语言除法溢出问题