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 个主要客户端,即 ios、android 和网络应用。 用户:将与您的一个客户端交互的最终用户,然后客户端将代表 Oauth 服务器进行通信。因此,您只需生成一次client_id
和client_secrete
。然后,您可以使用这些密钥作为 Oauth 服务器和最终用户之间的授权中间人。
在密码授予的情况下,client_key
和secrete_key
用于为您拥有的每个客户端的每个用户获取access_token
。
一旦客户端获得特定用户的access_token
(通常在登录时),客户端将不再需要发送client_key
和secrete_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 密码授予混淆的主要内容,如果未能解决你的问题,请参考以下文章
OpenId 连接和 OAuth 2.0 密码授予 - 有啥区别?
Grails OAuth2 登录密码凭据授予返回 invalid_client