OAuth2 密码授予混淆

Posted

技术标签:

【中文标题】OAuth2 密码授予混淆【英文标题】:OAuth2 password grant confusion 【发布时间】:2017-10-08 17:17:24 【问题描述】:

我已经阅读了下面的文章,这真是太棒了。那篇文章中的所有内容都很清楚,但我有一个主要疑问。

https://stormpath.com/blog/the-ultimate-guide-to-mobile-api-security

文章作者说在'OAuth2密码授权'中登录移动应用程序时,只需要发送电子邮件和密码即可从API服务器获取访问令牌,但我在很多地方读过你也需要在该请求中发送 client_id 和 client_secret。我将使用 Laravel 构建我的 API:

https://laravel.com/docs/master/passport#password-grant-tokens

在这里您可以看到它强制我在该请求中发送 client_id 和 client_secret。

我真的很困惑。如果我必须在该请求中发送 client_id 和 client_secret,首先我需要通过在授权服务器上创建一个客户端来获取它。那么在哪个事件中,我应该创建那个客户端?当用户尝试从移动应用程序登录时?我只需要知道确切的流程。

任何帮助将不胜感激。

谢谢

【问题讨论】:

【参考方案1】:

有两个不同的概念:

客户端:是用于与您的服务器通信的软件。通常,您将拥有 3 个主要客户端,即 iosandroid 和网络应用。 用户:将与您的一个客户端交互的最终用户,然后客户端将代表 Oauth 服务器进行通信。

因此,您只需生成一次client_idclient_secrete。然后,您可以使用这些密钥作为 Oauth 服务器和最终用户之间的授权中间人。

在密码授予的情况下,client_keysecrete_key 用于为您拥有的每个客户端的每个用户获取access_token

一旦客户端获得特定用户的access_token(通常在登录时),客户端将不再需要发送client_keysecrete_key,只需发送access_token

但是,如果该用户的 access_token 已过期,您将必须使用这些密钥将新的 access_token 与您从登录过程中收到的 refresh_token 交换。

【讨论】:

【参考方案2】:

我在名为ConfigurePassport 的迁移中创建了授权客户端,并设置了我希望应用程序使用的密钥。您不需要每个用户都有一个客户端。

public function up()

    /*
     * This command will create the encryption keys needed to generate secure access tokens.
     * In addition, the command will create "personal access" and "password grant"
     * clients which will be used to generate access tokens
     */
    Artisan::call( 'passport:install', array('-n' => true) );

    // Set Password Grant Client secret to known key
    DB::table( 'oauth_clients' )->where( 'password_client', 1 )->update(
        ['secret' => env( 'GRANT_CLIENT_SECRET', 'dfhsdfhbtg545fdf45yedh5f5blahblah' )]
    );

上述迁移根据文档运行 artisan 命令passport:install 来安装客户端。 https://laravel.com/docs/master/passport#password-grant-tokens

现在您的移动应用可以像这样请求令牌:每个用户的唯一参数是用户名和密码。

您可以在 oauth_clients 表中找到 password_client 为 true 的客户端 ID。可能是 2。

$http->post('http://your-app.com/oauth/token', [
    'form_params' => [
        'grant_type' => 'password',
        'client_id' => 2,
        'client_secret' => 'dfhsdfhbtg545fdf45yedh5f5blahblah',
        'username' => 'taylor@laravel.com',
        'password' => 'my-password',
        'scope' => '',
    ],
]);

【讨论】:

谢谢,如果你能详细解释一下就好了。 @ParthVora 添加了更多内容,您有什么特别遗漏的吗? 所以在应用程序中,我必须硬编码client_id和client_secret? 您可以这样做,或者将自定义登录路由添加到您的 api 作为包装器,该包装器接受用户/传递作为参数并构建 oauth 请求,包括客户端 ID 和密码,并将其发布到 oauth /令牌路线。这样以后改秘密就容易了。【参考方案3】:

为需要与 OAuth2 服务器集成的开发人员创建了一个客户端。它与特定用户的登录流程无关。

例如。我想与 Facebook 登录集成;我在 Facebook 上创建了一个客户端并将其合并到我的服务中,这是 Facebook 了解我的服务对象的方式。

因此,用户通过您的应用程序登录;然后,您的应用程序将该用户名和密码发送到后端服务器。然后后端服务器添加 client_id 和 secret,以便 OAuth 服务器可以验证请求的真实性。

因此,在您的情况下,用户登录您的移动应用程序,您将该登录请求(用户名和密码,使用 SSL)发送到您的后端服务器。然后,您的后端服务器将该请求转发到 OAuth2 服务,如下所示。

'form_params' => [
    'grant_type' => 'password',
    'client_id' => 'client-id',
    'client_secret' => 'client-secret',
    'username' => 'user@email.com',
    'password' => 'user-password',
    'scope' => '',
],

这会直接返回一个 access_token 和一个刷新令牌,您可以安全地存储在您的移动应用程序中。

【讨论】:

谢谢。只是为了让您知道我将同时构建应用程序和 API,因此图片中没有像 facebook 这样的第三方网站。如您所知,为了获取访问令牌、客户端 ID 和客户端密码是必需的,那么我是否应该创建它们并放入移动应用程序代码并在 API 请求中发送它们?在这种情况下,无论设备和用户如何,这些凭据都是相同的。 你不能把它们放在移动应用程序上,移动应用程序上的任何代码都是可拦截和直接可读的。任何人都可以反编译您的应用程序并读取您的 client_id 和 secret。查看laravel.com/docs/5.4/…,它可以满足您的一些需求。

以上是关于OAuth2 密码授予混淆的主要内容,如果未能解决你的问题,请参考以下文章

OAuth2 密码授予和基本身份验证

无法在 Spring Oauth2 密码授予中获取访问令牌

OpenId 连接和 OAuth 2.0 密码授予 - 有啥区别?

Grails OAuth2 登录密码凭据授予返回 invalid_client

如何获取 Spring Boot 和 OAuth2 示例以使用默认密码授予凭据以外的其他凭据

OAuth 2.0 中资源所有者密码凭据授予类型的用途是啥?