mirror of
https://github.com/yiisoft/yii2.git
synced 2025-11-08 08:56:23 +08:00
Support for other auth types.
This commit is contained in:
@ -75,9 +75,9 @@ class User extends ActiveRecord implements IdentityInterface
|
|||||||
/**
|
/**
|
||||||
* @inheritdoc
|
* @inheritdoc
|
||||||
*/
|
*/
|
||||||
public static function findIdentityByToken($token)
|
public static function findIdentityByAccessToken($token)
|
||||||
{
|
{
|
||||||
throw new NotSupportedException('"findIdentityByToken" is not implemented.');
|
throw new NotSupportedException('"findIdentityByAccessToken" is not implemented.');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -8,7 +8,7 @@ class User extends \yii\base\Object implements \yii\web\IdentityInterface
|
|||||||
public $username;
|
public $username;
|
||||||
public $password;
|
public $password;
|
||||||
public $authKey;
|
public $authKey;
|
||||||
public $apiKey;
|
public $accessToken;
|
||||||
|
|
||||||
private static $users = [
|
private static $users = [
|
||||||
'100' => [
|
'100' => [
|
||||||
@ -16,14 +16,14 @@ class User extends \yii\base\Object implements \yii\web\IdentityInterface
|
|||||||
'username' => 'admin',
|
'username' => 'admin',
|
||||||
'password' => 'admin',
|
'password' => 'admin',
|
||||||
'authKey' => 'test100key',
|
'authKey' => 'test100key',
|
||||||
'apiKey' => '100-apikey',
|
'accessToken' => '100-token',
|
||||||
],
|
],
|
||||||
'101' => [
|
'101' => [
|
||||||
'id' => '101',
|
'id' => '101',
|
||||||
'username' => 'demo',
|
'username' => 'demo',
|
||||||
'password' => 'demo',
|
'password' => 'demo',
|
||||||
'authKey' => 'test101key',
|
'authKey' => 'test101key',
|
||||||
'apiKey' => '101-apikey',
|
'accessToken' => '101-token',
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
@ -38,10 +38,10 @@ class User extends \yii\base\Object implements \yii\web\IdentityInterface
|
|||||||
/**
|
/**
|
||||||
* @inheritdoc
|
* @inheritdoc
|
||||||
*/
|
*/
|
||||||
public static function findIdentityByToken($token)
|
public static function findIdentityByAccessToken($token)
|
||||||
{
|
{
|
||||||
foreach (self::$users as $user) {
|
foreach (self::$users as $user) {
|
||||||
if ($user['apiKey'] === $token) {
|
if ($user['accessToken'] === $token) {
|
||||||
return new static($user);
|
return new static($user);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -30,9 +30,9 @@ class User extends ActiveRecord implements IdentityInterface
|
|||||||
* @param string $token the token to be looked for
|
* @param string $token the token to be looked for
|
||||||
* @return IdentityInterface|null the identity object that matches the given token.
|
* @return IdentityInterface|null the identity object that matches the given token.
|
||||||
*/
|
*/
|
||||||
public static function findIdentityByToken($token)
|
public static function findIdentityByAccessToken($token)
|
||||||
{
|
{
|
||||||
return static::find(['api_key' => $token]);
|
return static::find(['access_token' => $token]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -10,7 +10,7 @@ In particular, Yii provides support for the following aspects regarding RESTful
|
|||||||
* Proper formatting of collection data and validation errors;
|
* Proper formatting of collection data and validation errors;
|
||||||
* Efficient routing with proper HTTP verb check;
|
* Efficient routing with proper HTTP verb check;
|
||||||
* Support `OPTIONS` and `HEAD` verbs;
|
* Support `OPTIONS` and `HEAD` verbs;
|
||||||
* Authentication via HTTP basic;
|
* Authentication;
|
||||||
* Authorization;
|
* Authorization;
|
||||||
* Caching via `yii\web\HttpCache`;
|
* Caching via `yii\web\HttpCache`;
|
||||||
* Support for HATEOAS: TBD
|
* Support for HATEOAS: TBD
|
||||||
@ -27,22 +27,22 @@ Let's use a quick example to show how to build a set of RESTful APIs using Yii.
|
|||||||
Assume you want to expose the user data via RESTful APIs. The user data are stored in the user DB table,
|
Assume you want to expose the user data via RESTful APIs. The user data are stored in the user DB table,
|
||||||
and you have already created the ActiveRecord class `app\models\User` to access the user data.
|
and you have already created the ActiveRecord class `app\models\User` to access the user data.
|
||||||
|
|
||||||
First, check your `User` class for its implementation of the `findIdentityByToken()` method.
|
First, check your `User` class for its implementation of the `findIdentityByAccessToken()` method.
|
||||||
It may look like the following:
|
It may look like the following:
|
||||||
|
|
||||||
```php
|
```php
|
||||||
class User extends ActiveRecord
|
class User extends ActiveRecord
|
||||||
{
|
{
|
||||||
...
|
...
|
||||||
public static function findIdentityByToken($token)
|
public static function findIdentityByAccessToken($token)
|
||||||
{
|
{
|
||||||
return static::find(['api_key' => $token]);
|
return static::find(['access_token' => $token]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
This means your user table has a column named `api_key` which stores API access keys for the users.
|
This means your user table has a column named `access_token` which stores API access tokens for the users.
|
||||||
Pick up a key from the table as you will need it to access your APIs next.
|
Pick up a token from the table as you will need it to access your APIs next.
|
||||||
|
|
||||||
Second, create a controller class `app\controllers\UserController` as follows,
|
Second, create a controller class `app\controllers\UserController` as follows,
|
||||||
|
|
||||||
@ -86,7 +86,7 @@ for accessing the user data. The APIs you have created include:
|
|||||||
You may access your APIs with the `curl` command like the following,
|
You may access your APIs with the `curl` command like the following,
|
||||||
|
|
||||||
```
|
```
|
||||||
curl -i -u "Your-API-Key:" -H "Accept:application/json" "http://localhost/users"
|
curl -i -u "Your-API-Access-Token:" -H "Accept:application/json" "http://localhost/users"
|
||||||
```
|
```
|
||||||
|
|
||||||
which may give the following output:
|
which may give the following output:
|
||||||
@ -108,7 +108,7 @@ Content-Type: application/json; charset=UTF-8
|
|||||||
```
|
```
|
||||||
|
|
||||||
> Tip: You may also access your API via Web browser. You will be asked
|
> Tip: You may also access your API via Web browser. You will be asked
|
||||||
> to enter a username and password. Fill in the username field with the API key you obtained
|
> to enter a username and password. Fill in the username field with the API access token you obtained
|
||||||
> previously and leave the password field blank.
|
> previously and leave the password field blank.
|
||||||
|
|
||||||
Try changing the acceptable content type to be `application/xml`, and you will see the result
|
Try changing the acceptable content type to be `application/xml`, and you will see the result
|
||||||
@ -139,4 +139,57 @@ class User extends ActiveRecord
|
|||||||
|
|
||||||
In the following subsections, we will explain in more details about implementing RESTful APIs.
|
In the following subsections, we will explain in more details about implementing RESTful APIs.
|
||||||
|
|
||||||
TBD
|
|
||||||
|
HTTP Status Code Summary
|
||||||
|
------------------------
|
||||||
|
|
||||||
|
* `200`: OK. Everything worked as expected.
|
||||||
|
* `201`: A data item was successfully created. Please check the `Location` header for the URL to access the new data item.
|
||||||
|
* `204`: A data item was successfully deleted.
|
||||||
|
* `304`: Data not modified. You can use cached data.
|
||||||
|
* `400`: Bad request. This could be caused by various reasons from the user side, such as invalid content type request,
|
||||||
|
invalid API version number, or data validation failure. If it is data validation failure, please check
|
||||||
|
the response body for error messages.
|
||||||
|
* `401`: No valid API access token is provided.
|
||||||
|
* `403`: The authenticated user is not allowed to access the specified API endpoint.
|
||||||
|
* `404`: The requested item does not exist.
|
||||||
|
* `405`: Method not allowed. Please check the `Allow` header for allowed HTTP methods.
|
||||||
|
* `500`: Internal server error.
|
||||||
|
|
||||||
|
|
||||||
|
Data Formatting
|
||||||
|
---------------
|
||||||
|
|
||||||
|
|
||||||
|
Implementing New API Endpoints
|
||||||
|
------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
Routing
|
||||||
|
-------
|
||||||
|
|
||||||
|
|
||||||
|
Authentication
|
||||||
|
--------------
|
||||||
|
|
||||||
|
|
||||||
|
Authorization
|
||||||
|
-------------
|
||||||
|
|
||||||
|
|
||||||
|
Versioning
|
||||||
|
----------
|
||||||
|
|
||||||
|
|
||||||
|
Caching
|
||||||
|
-------
|
||||||
|
|
||||||
|
|
||||||
|
Rate Limiting
|
||||||
|
-------------
|
||||||
|
|
||||||
|
Documentation
|
||||||
|
-------------
|
||||||
|
|
||||||
|
Testing
|
||||||
|
-------
|
||||||
|
|||||||
@ -32,6 +32,14 @@ class Controller extends \yii\web\Controller
|
|||||||
* The name of the header parameter representing the API version number.
|
* The name of the header parameter representing the API version number.
|
||||||
*/
|
*/
|
||||||
const HEADER_VERSION = 'version';
|
const HEADER_VERSION = 'version';
|
||||||
|
/**
|
||||||
|
* HTTP Basic authentication.
|
||||||
|
*/
|
||||||
|
const AUTH_TYPE_BASIC = 'Basic';
|
||||||
|
/**
|
||||||
|
* HTTP Bearer authentication (the token obtained through OAuth2)
|
||||||
|
*/
|
||||||
|
const AUTH_TYPE_BEARER = 'Bearer';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var string|array the configuration for creating the serializer that formats the response data.
|
* @var string|array the configuration for creating the serializer that formats the response data.
|
||||||
@ -41,6 +49,14 @@ class Controller extends \yii\web\Controller
|
|||||||
* @inheritdoc
|
* @inheritdoc
|
||||||
*/
|
*/
|
||||||
public $enableCsrfValidation = false;
|
public $enableCsrfValidation = false;
|
||||||
|
/**
|
||||||
|
* @var string the authentication type. This should be a valid HTTP authentication method.
|
||||||
|
*/
|
||||||
|
public $authType = self::AUTH_TYPE_BASIC;
|
||||||
|
/**
|
||||||
|
* @var string the authentication realm to display in case when authentication fails.
|
||||||
|
*/
|
||||||
|
public $authRealm = 'api';
|
||||||
/**
|
/**
|
||||||
* @var string the chosen API version number
|
* @var string the chosen API version number
|
||||||
* @see supportedVersions
|
* @see supportedVersions
|
||||||
@ -150,15 +166,24 @@ class Controller extends \yii\web\Controller
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Authenticates the user.
|
* Authenticates the user.
|
||||||
* This method implements the user authentication based on HTTP basic authentication.
|
* This method implements the user authentication based on an access token sent through the `Authorization` HTTP header.
|
||||||
* @throws UnauthorizedHttpException if the user is not authenticated successfully
|
* @throws UnauthorizedHttpException if the user is not authenticated successfully
|
||||||
*/
|
*/
|
||||||
protected function authenticate()
|
protected function authenticate()
|
||||||
{
|
{
|
||||||
$apiKey = Yii::$app->getRequest()->getAuthUser();
|
$request = Yii::$app->getRequest();
|
||||||
if ($apiKey === null || !Yii::$app->getUser()->loginByToken($apiKey)) {
|
if ($this->authType == self::AUTH_TYPE_BASIC) {
|
||||||
Yii::$app->getResponse()->getHeaders()->set('WWW-Authenticate', 'Basic realm="api"');
|
$accessToken = $request->getAuthUser();
|
||||||
throw new UnauthorizedHttpException($apiKey === null ? 'Please provide an API key.' : 'You are requesting with an invalid API key.');
|
} else {
|
||||||
|
$authHeader = $request->getHeaders()->get('Authorization');
|
||||||
|
if ($authHeader !== null && preg_match("/^{$this->authType}\\s+(.*?)$/", $authHeader, $matches)) {
|
||||||
|
$accessToken = $matches[1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (empty($accessToken) || !Yii::$app->getUser()->loginByToken($accessToken)) {
|
||||||
|
Yii::$app->getResponse()->getHeaders()->set("WWW-Authenticate', '{$this->authType} realm=\"{$this->authRealm}\"");
|
||||||
|
throw new UnauthorizedHttpException(empty($accessToken) ? 'Access token required.' : 'You are requesting with an invalid access token.');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -58,7 +58,7 @@ interface IdentityInterface
|
|||||||
* Null should be returned if such an identity cannot be found
|
* Null should be returned if such an identity cannot be found
|
||||||
* or the identity is not in an active state (disabled, deleted, etc.)
|
* or the identity is not in an active state (disabled, deleted, etc.)
|
||||||
*/
|
*/
|
||||||
public static function findIdentityByToken($token);
|
public static function findIdentityByAccessToken($token);
|
||||||
/**
|
/**
|
||||||
* Returns an ID that can uniquely identify a user identity.
|
* Returns an ID that can uniquely identify a user identity.
|
||||||
* @return string|integer an ID that uniquely identifies a user identity.
|
* @return string|integer an ID that uniquely identifies a user identity.
|
||||||
|
|||||||
@ -213,7 +213,7 @@ class User extends Component
|
|||||||
{
|
{
|
||||||
/** @var IdentityInterface $class */
|
/** @var IdentityInterface $class */
|
||||||
$class = $this->identityClass;
|
$class = $this->identityClass;
|
||||||
$identity = $class::findIdentityByToken($token);
|
$identity = $class::findIdentityByAccessToken($token);
|
||||||
$this->setIdentity($identity);
|
$this->setIdentity($identity);
|
||||||
return $identity;
|
return $identity;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user