认证 本文未发布 发布文章

未匹配的标注

中间件是在应用程序中应用身份认证的最佳解决方案。
在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 that create a User object (e.g., the CreateUserByCredentialsTask) 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 the login params in order to configure this feature.
  • Adapt the ProxyApiLoginTransporter accordingly to support your new Login Fields. These fields need to be added to properties

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.

本文章首发在 LearnKu.com 网站上。

上一篇 下一篇
《L03 构架 API 服务器》
你将学到如 RESTFul 设计风格、PostMan 的使用、OAuth 流程,JWT 概念及使用 和 API 开发相关的进阶知识。
《L02 从零构建论坛系统》
以构建论坛项目 LaraBBS 为线索,展开对 Laravel 框架的全面学习。应用程序架构思路贴近 Laravel 框架的设计哲学。
讨论数量: 0
发起讨论 只看当前版本


暂无话题~