使用 Laravel API 实现 OAuth 2.0 身份验证

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/24102459/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-14 09:37:11  来源:igfitidea点击:

Implementing OAuth 2.0 authentication with a Laravel API

phpangularjsauthenticationlaraveloauth

提问by John Dorean

I'm currently building a web application which is an AngularJS frontend that communicates with a RESTful API built using Laravel. I'm making good progress, but finding it hard to get my head around how to handle user authentication.

我目前正在构建一个 Web 应用程序,它是一个 AngularJS 前端,它与使用 Laravel 构建的 RESTful API 进行通信。我正在取得良好的进展,但发现很难理解如何处理用户身份验证。

I've been advised that I should be using OAuth for authentication, and I've decided to use it seen as it could be a learning experience for me as well. The package I'm using to handle this is oauth2-server-laravel.

有人建议我应该使用 OAuth 进行身份验证,我决定使用它,因为它对我来说也是一种学习体验。我用来处理这个的包是oauth2-server-laravel

The basic user story is that users can register their username/password combination for the application, and they then log into the application with that same username and password. They're only authenticated by their username and password, and not by any client secret. After login, they should be given an access token which will be send along with every future request to authenticate them on different API endpoints.

基本的用户故事是用户可以为应用程序注册他们的用户名/密码组合,然后他们使用相同的用户名和密码登录应用程序。他们仅通过用户名和密码进行身份验证,而不通过任何客户端机密进行身份验证。登录后,他们应该获得一个访问令牌,该令牌将与未来的每个请求一起发送,以在不同的 API 端点上对他们进行身份验证。

The OAuth2 library has a "password flow" grant type which seems to be what I need, however it also takes client_idand client_secretparameters, which I don't want. The request URI is something like this:

OAuth2 库有一个“密码流”授权类型,这似乎是我需要的,但它也需要client_idclient_secret参数,这是我不想要的。请求 URI 是这样的:

POST https://www.example.com/oauth/access_token?
grant_type=password&
client_id=the_client_id&
client_secret=the_client_secret&
username=the_username&
password=the_password&
scope=scope1,scope2&
state=123456789

But what I want is just:

但我想要的只是:

POST https://www.example.com/oauth/access_token?
grant_type=password&
username=the_username&
password=the_password

How am I meant to provide a client ID and secret of a user that has yet to authenticate?

我打算如何提供尚未进行身份验证的用户的客户端 ID 和机密?

Is there a different grant I can be using, or is what I want to achieve just not suited for OAuth at all?

我是否可以使用不同的授权,或者我想要实现的目标根本不适合 OAuth?

回答by plunntic iam

Take into account, that client idand client secretaren't parameters that you have to force your end-user to pass. They are static and defined in/for your client app (angular app in this case).

考虑到,这client idclient secret不是您必须强制最终用户传递的参数。它们是静态的,并在您的客户端应用程序中/为您的客户端应用程序(在这种情况下为角度应用程序)定义。

All you need to do is to create a record for your main app in oauth_clientstable, and create a scope with full access in oauth_scopestable, and send this values when requesting token.

您需要做的就是在oauth_clients表中为您的主应用程序创建一个记录,并在表中创建一个具有完全访问权限的范围oauth_scopes,并在请求令牌时发送此值。

And that's all in fact.

事实上,这就是全部。

Also, you may want to consider using implicit grant flow in case of building js-only application, because storing client secret and refresh token in a js app is insecure. Using implicit grant in a final product may look like login window on soundcloud and is more secure as the token is obtained server-side without exposing client secret.

此外,您可能需要考虑在构建纯 js 应用程序的情况下使用隐式授权流,因为在 js 应用程序中存储客户端机密和刷新令牌是不安全的。在最终产品中使用隐式授权可能看起来像 soundcloud 上的登录窗口,并且更安全,因为令牌是在服务器端获取的,而不会暴露客户端机密。

Another way to go, if you still want to use password flow is creating a proxy for refreshing tokens. Proxy can hide your refresh token in encrypted http-only cookie, and your js-app don't ask your api for new token, but the proxy instead. Proxy reads refresh token from encrypted cookie, asks the api for new token and returns it. So the refresh token is never exposed. If you set token ttl for an hour let's say, then stealing a token would be quite "pointless*" in case of a normal application, and stealing refresh token would be "impossible*".

另一种方法是,如果您仍想使用密码流,则创建用于刷新令牌的代理。代理可以将您的刷新令牌隐藏在加密的 http-only cookie 中,并且您的 js-app 不会向您的 api 询问新令牌,而是向代理询问。代理从加密的 cookie 中读取刷新令牌,向 api 请求新令牌并返回它。所以刷新令牌永远不会暴露。如果您将令牌 ttl 设置为一个小时,那么在正常应用程序的情况下,窃取令牌将是“毫无意义的*”,而窃取刷新令牌将是“不可能的*”。

*Of course if someone really want he probably could hack it any way.

*当然,如果有人真的想要他可能会以任何方式破解它。

And yeah, i know this all looks a bit hacky - modal windows for logging in, proxy etc. But also searching on this topic i couldn't find any better and more elegant way of doing it. I think that's still a lack that all js-apps have to deal with if you want a token based authentication.

是的,我知道这一切看起来有点 hacky - 用于登录、代理等的模态窗口。但也在搜索这个主题时,我找不到任何更好、更优雅的方式来做这件事。我认为如果你想要一个基于令牌的身份验证,这仍然是所有 js 应用程序必须处理的一个缺陷。

回答by Antoine Augusti

You are missing something with the OAuth specification. The client_idand client_secretare really important when asking for an access token when using the password method of OAuth v2. In fact, they are important for every method that gives you an access token. They identify the application or the server that has perform the request.

您缺少 OAuth 规范中的某些内容。在使用 OAuth v2 的密码方法时要求访问令牌时,client_idclient_secret非常重要。事实上,它们对于为您提供访问令牌的每种方法都很重要。它们标识执行请求的应用程序或服务器。

For example, let's say you have your API, 2 mobile applications and another server that do some tasks with your API. You will create 3 clients with their own client_idand client_secret. If your application has various access levels (they are called scopesin OAuth v2), the client_idcorresponding to the other server will be able to call functions of your API that require the scope adminwhereas your mobile application will only be able to call functions of your API that require the basicscope if you have defined scopes like this.

例如,假设您有自己的 API、2 个移动应用程序和另一个使用您的 API 执行某些任务的服务器。您将创建 3 个具有自己client_idclient_secret. 如果您的应用程序具有各种访问级别(它们scopes在 OAuth v2 中被调用),则client_id对应于其他服务器的将能够调用您的 API 需要范围的函数,admin而您的移动应用程序将只能调用您的 API 的函数basic如果您已经定义了这样的范围,则需要范围。

If your API grows up in the future, this is really essential. Another example, let's imagine you have given an API key (a pair client_idand client_secret) to one of your friend and he has build a nice mobile app with your API. If one day he starts doing naughty things with your API, you can't stop him very easily. Whereas you could have just removed his key pair if you had followed OAuth v2 principles.

如果你的 API 在未来成长起来,这真的很重要。再举一个例子,假设您将一个 API 密钥(一对client_idclient_secret)提供给您的一位朋友,他已经使用您的 API 构建了一个不错的移动应用程序。如果有一天他开始用你的 API 做一些淘气的事情,你不能很容易地阻止他。而如果您遵循 OAuth v2 原则,您就可以删除他的密钥对。

OAuth v2 is not an easy thing to understand, take the time to read specifications and good tutorials before developing your API.

OAuth v2 不是一件容易理解的事情,在开发 API 之前花时间阅读规范和好的教程。

Some useful links :

一些有用的链接:

回答by Jannie Theunissen

Just to add a bit to plunntic's excellent answer: remember "client" is not related to "user", so when I use a password flow I just define the client_id and client_secret as constants on the AngularJS app to tell the api backend: hey, this is the browser app that is being used to request a token.

只是为 plunntic 的优秀答案添加一点:记住“客户端”与“用户”无关,因此当我使用密码流时,我只是将 client_id 和 client_secret 定义为 AngularJS 应用程序上的常量,以告诉 api 后端:嘿,这是用于请求令牌的浏览器应用程序。