如何使用基于OAuth2浏览器的认证,然后在服务器上验证记录


How to use OAuth2 Browser based authentication, and then verify the record on the server

我有一个基于浏览器的应用程序(单页,AngularJS),我使用hello使用第三方登录,如谷歌,FB, Soundcloud等。

我的应用使用PHP API服务器。

让用户能够使用Google登录,但也在服务器端验证用户的好方法是什么?

我正在考虑:

  • 浏览器应用通过google/fb/etc执行隐式授予
  • 然后,我将access_token从客户端传输到服务器,然后使用,例如,google-api-php-client与我的app id, secret和用户access_token ?使用他们的API,如/me ?(这是哪种授权类型?)
  • 从第三方(facebook_id, email等)检索一些密钥,将其与我的数据库中的用户进行匹配,然后考虑用户身份验证?

另外,我应该对每个API请求执行此操作吗?或者我应该将access_token暂时隐藏起来,并假设用户在密钥过期之前仍然有效?

一个问题是,并非所有这些提供程序都支持隐式流。但是假设他们这样做了,您为每个用户获得的access_token将证明用户使用该系统进行了身份验证,而不一定证明他们有权调用您的 API。您仍然需要一些东西来断言"someone@gmail.com可以'读取'系统中的资源X "

你可能需要一些东西来翻译你从Google, Soundcloud等得到的任何东西到你的应用程序可以理解的令牌。一个简单的(r)格式是使用JWT。(Json Web Tokens).

App -> Intermmediary -> Soundcloud/Google <-JWT--+ <---whavetever-+

然后:

App - (JWT) -> API

JWT易于操作、验证和验证。看到jwt.io

你可能也想看看这篇博客文章,以获得一些额外的信息(特别是关于AngularJS前端的)

上面提到的博客@eugenio-pace对于设置客户端非常有帮助。

对于服务器端,access_token应该被验证。

SDK是(在composer中)(代码如下):

    Facebook: "facebook/php-sdk-v4" : "4.0.*"
  • Google: cURL请求(不关心"google/apiclient")
  • SoundCloud: "ise/php-soundcloud": "3.*"

(当然还有其他的,只有这三个是我选择的,看起来很不错。)

上次我做了类似的事情,我犯了在每个请求上验证access_token的错误,这对性能产生了巨大的(显然是负面的)影响。现在我只需在登录时验证它,并使用它从该服务检索用户的ID。所以,浏览器向我发送access_token A,并说它来自Facebook,我使用Facebook的access_token上面的sdk,我得到他们的ID,所以我知道他们是他们说他们是谁。

我建议将access_tokenexpires_in一起存储在服务器上。

(我还没有处理刷新令牌)

使用上述库验证令牌的代码:

function validateTokenFacebook($token, $id=null) {
    // Performed above
    // FacebookSession::setDefaultApplication($config->fb->app_id, $config->fb->secret);
    $session = new FacebookSession($token);
    // Fetch user info
    $request = new FacebookRequest($session, 'GET', '/me');
    try {
        $response = $request->execute();
    } catch ('Facebook'FacebookServerException $e) {
        $this->mlog->err($e . "'n" . $e->getTraceAsString());
        throw new AuthTokenInvalidException();
    }
    $graphObject = $response->getGraphObject();
    $user_id = $graphObject->getProperty('id');
    return array(access_token, $user_id);
}
function validateTokenGoogle($token, $id=null) {
    $resp=array();
    // This key isn't included in the token from hello.js, but
    // google needs it
    if (!array_key_exists('created', $token)) $token['created'] = $token['expires'] - $token['expires_in'];
    $client = new 'Google_Client();
    $client->setClientId($this->systemConfig->google->app_id);
    $client->setClientSecret($this->systemConfig->google->secret);
    $client->setRedirectUri($this->systemConfig->google->redirectUri);
    $client->setScopes('email');
    $client->setAccessToken(json_encode($token));
    try {
        // Send Client Request
        $objOAuthService = new 'Google_Service_Oauth2($client);
        $userData = $objOAuthService->userinfo->get();
        return array($token['access_token'], $userData['id']);
    } catch ('Google_Auth_Exception $e) {
        throw new AuthException('Google returned ' . get_class($e));
    }
}
function validateTokenSoundcloud($token, $id=null) {
    $soundcloud = new 'Soundcloud'Service(
        $this->systemConfig->soundcloud->app_id,
        $this->systemConfig->soundcloud->secret,
        $this->systemConfig->soundcloud->redirect);
    $soundcloud->setAccessToken($access_token);
    try {
        $response = json_decode($soundcloud->get('me'), true);
        if (array_key_exists('id', $response))
            return array($access_token, $response['id']);
    } catch (Soundcloud'Exception'InvalidHttpResponseCodeException $e) {
        $this->mlog->err($e->getMessage());
    }
    throw new AuthTokenInvalidException();
}

我在上面有一些自定义类,比如Exceptions和systemConfig,但我认为它足够冗长,可以传达它们的功能。

相关文章: