认证 本文未发布 发布文章
中间件是在应用程序中应用身份认证的最佳解决方案。
在Apiato中我们能够使用两个 Authentication Middlewares
保护我们的路由点:
- Api的授权:
auth:api
- web的授权:
auth:web
Api 认证 (OAuth 2.0)
为了防止未经身份认证的用户访问API路有点,可以使用 auth:api
中间件。
<?php
$router->get('secret/info', [
'uses' => 'Controller@getSecretInfo',
'middleware' => [
'auth:api',
],
]);
所有受 auth:api
保护的路由只有在发送有效访问令牌时才可访问。
该中间件由Laravel Passport包提供。因此,您可以阅读它的文档了解更多细节。
如何使用OAuth 2.0获取访问令牌
记录所有Auth端点。可以转到文档生成器页面,了解如何生成API文档并阅读它们。
概览
OAuth让你用不同的方法进行身份认证,这些方法被称作为 grants
,如何决定使用哪个认证类型,你可以点击这里,了解完后,继续阅读本文档。
定义:
- 客户端凭据:是
client_id
&client_secret
。 - 代理:只是一个路由入口而已,你可以调用而不是直接访问认证服务器,代理入口将会将客户端的凭据附加到请求的中调用认证服务器,然后返回其响应。每一个自有的客户端应用程序一概具有自己的代理入口(至少一个登录和一个令牌刷新),默认情况下,Apiato 提供
Admin Web Client
的路由端点。
自有的客户端可以使用代理或者不使用代理认证登录。然而第三方客户端只能没有代理登录。(刷新token同理)
自有客户端:
- 使用代理 << 最好和最容易实现的方法, (需要手动生成客户机,为每个客户机创建代理端点)
- 不使用代理 <<如果前端没有公开客户端凭据,则可以无需代理直接调用身份验证服务器端点。
第三方客户端:- 不使用代理 << 您不需要第三方客户机的代理,因为它们通常从后端与保护客户机凭据的API集成。
A:自有客户端
自有客户端 (您的前端移动、Web、……应用程序)通常调用您的私有的API (内部API).
对于自有客户端,你需要使用资源拥有者凭据认证(AKA密码授予令牌)。
使用此授权类型时,你的服务器需要认证客户端应用程序(确保请求来自您可信的前端应用程序),然后需要检查用户的凭据是否正确(确保用户是已经注册并具有正确的访问权限),在认证发放令牌前。
注意:
- 在注册时:API需要返回用户数据,你需要记录这个用户(使用他传递的相同凭据)以获得访问令牌来调用API。
- 在登录时:API返回具有刷新的用户访问令牌,你需要通过使用其他的访问令牌再次调用用户端点来请求用户数据。
如何运作:
1)在数据库中创建一个密码类型客户端来代表您的某个应用程序(例如:移动应用程序)。使用 php artisan passport:client --password
生成客户端。
2)注册后,用户可以在App登录界面输入他的(用户名+密码)。
3)您的应用程序应发送Post请求以http://api.apiato.develop/v1/oauth/token包含用户凭据(username和password)以及客户端凭据(client_id和client_secret)scope 以及和grant_type=password:
请求:
curl --request POST \
--url http://api.apiato.develop/v1/oauth/token \
--header 'accept: application/json' \
--header 'content-type: application/x-www-form-urlencoded' \
--data 'username=admin%40admin.com&password=admin&client_id=2&client_secret=SGUVv02b1ppQCgI7ZVeoTZDN6z8SSFLYiMOzzfiE&grant_type=password&scope='
响应:
{
"token_type": "Bearer",
"expires_in": 31536000,
"access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUz...",
"refresh_token": "TPSPA1S6H8Wydjkjl+xt+hPGWTagL..."
}
4)你的客户端 App 将保存Tokens和通过将票据放入HTTP头中 Authorization = Bearer {Access-Token}
. 安全的访问数据,更多的信息你可以查看 Laravel Passport Here
警告:客户端ID和密钥不应存储在JavaScript或浏览器缓存中,也不应以任何方式访问。因此,在WebApps(JavaScript) 的情况下,您需要隐藏代理后的客户端凭据。默认情况下,Apiato 为你提供了一个登录的代理服务器,可以用于所有可信的自有客户端,我们将在下面介绍如何使用它们。
自有客户端有代理的登录
概念:为每个可信客户端创建用于登录的端点。
默认请款下,Apiato 为你的 Web管理后台准备了一个clients/web/admin/login
url ,你可以根据你的需要为每一个你信任的自有客户端添加url (例如:: clients/web/users/login
,clients/mobile/users/login
)。
Behind the scene, that endpoint is appending the corresponding client ID and Secret to your request and making another call to your Auth server with all the required data. (this way the client does not need to send the ID and Secret with the request, and he is using his own URL which gives even more control to which client is accessing your Server). Then it returns the Auth response back to the client with the Tokens in it.
Note: You have to manually extract the Client credentials from the DB and put them in the .env
, for each client.
When running passport:install
it automatically creates one client for you with ID 2, so you can use that for your first app. Or you can use php artisan passport:client --password
to generate them..env
Example:
CLIENT_WEB_ADMIN_ID=2
CLIENT_WEB_ADMIN_SECRET=VkjYCUk5DUexJTE9yFAakytWCOqbShLgu9Ql67TI
Login without Proxy for first-party clients
Login from your App by sending a POST request to http://api.apiato.develop/v1/oauth/token
with grant_type=password
, the User credentials (username
& password
), Client Credentials (client_id
& client_secret
) and finally the scope
which could be empty.
B: For third-party clients
Third party clients (User’s custom external Apps, who wants to integrate with your Software) always consumes your public API (External API) only.
For third-party clients you need to use the Client credentials grant (A.K.A Personal Access Tokens). This grant type is the simplest and is suitable for machine-to-machine authentication.
With this grant type your server needs to authenticate the Client App only, before issuing an access token.
How it works
1) User logs in to your Clients App Interface (an external App made for your users only), go to settings, create Client (of type personal) and copy the ID and Secret. (Note this can be done via an API if you prefer)
You may generate a personal client for testing purposes using php artisan passport:client --personal
.
2) User add the Client credentials to his “Server Side software” and send a Post request to http://api.apiato.develop/v1/oauth/token
containing the Client credentials (client_id
and client_secret
) in addition to the scope
and grant_type=client_credentials:
Request:
curl --request POST \
--url http://api.apiato.develop/v1/oauth/token \
--header 'accept: application/json' \
--header 'content-type: application/x-www-form-urlencoded' \
--data 'client_id=1&client_secret=y1RbtnOvh9rpA91zPI2tiVKmFlepNy9dhHkzUKle&grant_type=client_credentials&scope='
Response:
{
"token_type": "Bearer",
"expires_in": 31536000,
"access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1Ni...",
"refresh_token": "ZFDPA1S7H8Wydjkjl+xt+hPGWTagX..."
}
3) The Client will be granted an Access Token to be saved. Then the Client can start requesting secure data, by sending the Access Token in the HTTP Header Authorization = Bearer {Access-Token}
.
Note: When a new user is registered, will be issued a personal Access Token automatically. Check the User “Registration page”.
More info at Laravel Passport Here
Login without Proxy for third-party clients
We usually do not need a proxy for third-party clients as they are most likely making calls form their servers, thus the Client ID and Secret should be secure and not exposed to the users.
Login by sending a POST request to http://api.apiato.develop/v1/oauth/token
with grant_type=client_credentials
, Client Credentials (client_id
& client_secret
) and finally the scope
which could be empty.
Once issued, you can use that Access Token to make requests to protected resources (Endpoints). The Access Token should be sent in theAuthorization
header of type Bearer
(Example: Authorization = Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUz...
)
Keep in mind there’s no session state when using Tokens for Authentication
Login With Custom Attributes
This feature is supported with Apiato 7.4.
By default, Apiato allows Users
to log in with their email
address. However, you may want to also allow username
and phone
to login your users.
Here is, how to configure and use this feature.
- You may need to adapt your database accordingly (e.g., add the respective field to the
users
table). - You may need to adapt the
Task
thatcreate
aUser
object (e.g., theCreateUserByCredentialsTask
) accordingly to support the new fields. This may also affect your Register logic. - Check the
App\Containers\Authentication\Configs\authentication-container
Configuration file and check thelogin
params in order to configure this feature. - Adapt the
ProxyApiLoginTransporter
accordingly to support your new Login Fields. These fields need to be added toproperties
Logout
Logout by sending a DELETE
request to http://api.apiato.develop/v1/logout/
containing the Token in the Header.
{
"message": "Token revoked successfully."
}
Responses
Authentication failed JSON response:
{
"errors": "Missing or invalid Access Token!",
"status_code": 403,
"message": "Unauthenticated."
}
Wrong Client ID or Secret:
{
"error": "invalid_client",
"message": "Client authentication failed"
}
Access Correct:
{
"token_type": "Bearer",
"expires_in": 31500,
"access_token": "tnJ1eXAiOiJKV1QiLCJhbGciOiJSUzI1Zx...",
"refresh_token": "ZFDPA1S7H8Wydjkjl+xt+hPGWTagX..."
}
Change Tokens Expiration dates
Go to the app/Ship/Configs/apiato.php
config file and edit this:
<?php
/*
|--------------------------------------------------------------------------
| Access Token Expiration
|--------------------------------------------------------------------------
|
| In Days. Default to 3650 days = 10 years
|
*/
'expires-in' => env('API_TOKEN_EXPIRES', 3650),
/*
|--------------------------------------------------------------------------
| Refresh Token Expiration
|--------------------------------------------------------------------------
|
| In Days. Default to 3650 days = 10 years
|
*/
'refresh-expires-in' => env('API_REFRESH_TOKEN_EXPIRES', 3650),
To change from days to minutes you need to edit the boot
function in App\Containers\Authentication\Providers\AuthProvider
.
Web Authentication
To protect an Web Endpoint from being accessible by unauthenticated users you can use the auth:web
Middleware.
Example:
<?php
$router->get('private/page', [
'uses' => 'Controller@showPrivatePage',
'middleware' => [
'auth:web',
],
]);
This Middleware is provided by apiato and is different than the default Laravel Auth Middleware.
If authentication failed, users will be redirected to a login page
To change the login page view go to the config file app/Ship/Configs/apiato.php
, and set the name of your login page there as follow:
<?php
/*
|--------------------------------------------------------------------------
| The Login Page URL
|--------------------------------------------------------------------------
*/
'login-page-url' => 'login',
This will be looking for (login.html or login.php or login.blade.php).
Refresh Token
In case your server is issuing a short-lived access tokens, the users will need to refresh their access tokens via the refresh token that was provided to them when the access token was issued.
Refresh Token with proxy for first-party clients
By default Apiato provide this ready endpoint http://api.apiato.develop/v1/clients/web/admin/refresh
for the Web Admin Dashboard Client to be used when you need to refresh token for that client. You can of course create as many other endpoints as you want for each client. See the code of (app/Containers/Authentication/UI/API/Routes/ProxyRefreshForAdminWebClient.v1.public.php
) and create similar one for each client. The most important change will be the env('CLIENT_WEB_ADMIN_ID')
and env('CLIENT_WEB_ADMIN_SECRET')
, passed to the ProxyApiRefreshAction
.
Those proxy refresh endpoints work in 2 ways. Either by passing the refresh_token
manually to the endpoint. Or by passing it with the HttpCookie. In both cases the code will work and the server will reply with a response similar to this:
{
"token_type": "Bearer",
"expires_in": 31500,
"access_token": "tnJ1eXAiOiJKV1QiLCJhbGciOiJSUzI1Zx...",
"refresh_token": "ZFDPA1S7H8Wydjkjl+xt+hPGWTagX..."
}
Containing new Access Token and new Refresh Token.
Refresh Token without proxy for first-party or third-party clients
The request to http://api.apiato.develop/v1/oauth/token
should contain grant_type=refresh_token
, the client_id
& client_secret
, in addition to the refresh_token
and finally the scope
which could be empty.
Force Email Confirmation
By default a user does not have to confirm his email address to be able to login. However, to force users to confirm their email (prevent unconfirmed users from accessing the site), you can set 'require_email_confirmation' => true
, in App\Containers\Authentication\Configs\authentication.php
.
When email confirmation is enabled (value set to true
), the API throws an exception, if the User
is not yet confirmed
.
Reset Password
Use the /password-forgot
(app/Containers/User/UI/API/Routes/ForgotPassword.v1.public.php
) and /password-reset
(app/Containers/User/UI/API/Routes/ResetPassword.v1.public.php
) endpoints.
First you need to send a request to the /password-forgot
endpoint. It will send you an email with a link when you make a request to that link, it will call the /password-reset
endpoint.
Note: For security reason, make sure the reset password URL is set in app/Containers/User/Configs/user-container.php
, and given to the client App, to be sent as parameter when calling the /password-forgot
.
Note: You must setup the email to get this function to work, however for testing purposes set the MAIL_DRIVER=log
in your .env
file in order to the see the email content in the log file laravel.log
.
Social Authentication
For Social Authentication visit the Social Authentication page.
推荐文章: