Commit 7a04dbaa by Qiang Xue

Support for other auth types.

parent 7b46dc34
......@@ -75,9 +75,9 @@ class User extends ActiveRecord implements IdentityInterface
/**
* @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 $password;
public $authKey;
public $apiKey;
public $accessToken;
private static $users = [
'100' => [
......@@ -16,14 +16,14 @@ class User extends \yii\base\Object implements \yii\web\IdentityInterface
'username' => 'admin',
'password' => 'admin',
'authKey' => 'test100key',
'apiKey' => '100-apikey',
'accessToken' => '100-token',
],
'101' => [
'id' => '101',
'username' => 'demo',
'password' => 'demo',
'authKey' => 'test101key',
'apiKey' => '101-apikey',
'accessToken' => '101-token',
],
];
......@@ -38,10 +38,10 @@ class User extends \yii\base\Object implements \yii\web\IdentityInterface
/**
* @inheritdoc
*/
public static function findIdentityByToken($token)
public static function findIdentityByAccessToken($token)
{
foreach (self::$users as $user) {
if ($user['apiKey'] === $token) {
if ($user['accessToken'] === $token) {
return new static($user);
}
}
......
......@@ -30,9 +30,9 @@ class User extends ActiveRecord implements IdentityInterface
* @param string $token the token to be looked for
* @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;
* Efficient routing with proper HTTP verb check;
* Support `OPTIONS` and `HEAD` verbs;
* Authentication via HTTP basic;
* Authentication;
* Authorization;
* Caching via `yii\web\HttpCache`;
* 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,
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:
```php
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.
Pick up a key from the table as you will need it to access your APIs next.
This means your user table has a column named `access_token` which stores API access tokens for the users.
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,
......@@ -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,
```
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:
......@@ -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
> 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.
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.
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.
*/
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.
......@@ -42,6 +50,14 @@ class Controller extends \yii\web\Controller
*/
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
* @see supportedVersions
*/
......@@ -150,15 +166,24 @@ class Controller extends \yii\web\Controller
/**
* 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
*/
protected function authenticate()
{
$apiKey = Yii::$app->getRequest()->getAuthUser();
if ($apiKey === null || !Yii::$app->getUser()->loginByToken($apiKey)) {
Yii::$app->getResponse()->getHeaders()->set('WWW-Authenticate', 'Basic realm="api"');
throw new UnauthorizedHttpException($apiKey === null ? 'Please provide an API key.' : 'You are requesting with an invalid API key.');
$request = Yii::$app->getRequest();
if ($this->authType == self::AUTH_TYPE_BASIC) {
$accessToken = $request->getAuthUser();
} 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
* 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.
* @return string|integer an ID that uniquely identifies a user identity.
......
......@@ -213,7 +213,7 @@ class User extends Component
{
/** @var IdentityInterface $class */
$class = $this->identityClass;
$identity = $class::findIdentityByToken($token);
$identity = $class::findIdentityByAccessToken($token);
$this->setIdentity($identity);
return $identity;
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment