Based on the laravel defaultauth
Implement API authentication
Microservices are becoming more and more popular. A lot of things are broken up into separate systems that have no direct relationship to each other. So if we do user authentication must be unified to do an independent user authentication system, rather than each business system to write again user authentication related things. However, there is a problem. Laravel’s default Auth authentication is done based on the database. What about microservice architecture?
The implementation code is as follows:
UserProvider interface:
// Obtain the authentication model by unique identifier
public function retrieveById($identifier);
// Obtain the model from the unique identifier and remember token
public function retrieveByToken($identifier, $token);
// Update the remember token with the given authentication model
public function updateRememberToken(Authenticatable $user, $token);
// Obtain the user with the given credentials, such as email, username, etc
public function retrieveByCredentials(array $credentials);
// Authenticates whether a given user matches a given credential
public function validateCredentials(Authenticatable $user, array $credentials);
Copy the code
Laravel has two default user providers: DatabaseUserProvider & EloquentUserProvider. DatabaseUserProvider Illuminate\Auth\DatabaseUserProvider
The authentication model is obtained directly from the database table.
EloquentUserProvider Illuminate\Auth\EloquentUserProvider
Get the authentication model using the Eloquent model
Based on this knowledge, it is easy to customize an authentication.
The customProvider
Create a custom authentication model that implements the Authenticatable interface;
App\Auth\UserProvider.php
namespace App\Auth;
use App\Models\User;
use Illuminate\Contracts\Auth\Authenticatable;
use Illuminate\Contracts\Auth\UserProvider as Provider;
class UserProvider implements Provider
{
/**
* Retrieve a user by their unique identifier.
* @param mixed $identifier
* @return \Illuminate\Contracts\Auth\Authenticatable|null
*/
public function retrieveById($identifier)
{
return app(User::class)::getUserByGuId($identifier);
}
/**
* Retrieve a user by their unique identifier and "remember me" token.
* @param mixed $identifier
* @param string $token
* @return \Illuminate\Contracts\Auth\Authenticatable|null
*/
public function retrieveByToken($identifier, $token)
{
return null;
}
/**
* Update the "remember me" token for the given user in storage.
* @param \Illuminate\Contracts\Auth\Authenticatable $user
* @param string $token
* @return bool
*/
public function updateRememberToken(Authenticatable $user, $token)
{
return true;
}
/**
* Retrieve a user by the given credentials.
* @param array $credentials
* @return \Illuminate\Contracts\Auth\Authenticatable|null
*/
public function retrieveByCredentials(array $credentials)
{
if(!isset($credentials['api_token']) {return null;
}
return app(User::class)::getUserByToken($credentials['api_token']);
}
/**
* Rules a user against the given credentials.
* @param \Illuminate\Contracts\Auth\Authenticatable $user
* @param array $credentials
* @return bool
*/
public function validateCredentials(Authenticatable $user, array $credentials)
{
if(!isset($credentials['api_token']) {return false;
}
return true; }}Copy the code
Authenticatable interface:
Illuminate\Contracts\Auth\Authenticatable Authenticatable defines an interface that a model or class needs to implement that can be used for authentication. That is, if a custom class is needed for authentication, the methods defined by this interface need to be implemented.
.// Get the field name that uniquely identifies and can be used for authentication, such as ID, UUID
public function getAuthIdentifierName(a);
// Get the value corresponding to the identifier
public function getAuthIdentifier(a);
// Obtain the password for authentication
public function getAuthPassword(a);
// Obtain the remember token
public function getRememberToken(a);
// Set remember token
public function setRememberToken($value);
// Obtain the name of a remember_token field, such as the default 'remember_token'
public function getRememberTokenName(a); .Copy the code
The Authenticatable trait defined in Laravel is also the trait used by the default User model of Laravel Auth. This trait defines the default authentication identifier for the User model to be ‘ID’ and the password field to be password. Remember_token and so on. Some Settings can be changed by overriding these methods of the User model.
Implement a custom authentication model
App\Models\User.php
namespace App\Models;
use App\Exceptions\RestApiException;
use App\Models\Abstracts\RestApiModel;
use Illuminate\Contracts\Auth\Authenticatable;
class User extends RestApiModel implements Authenticatable
{
protected $primaryKey = 'guid';
public $incrementing = false;
protected $keyType = 'string';
/** * get the name of the unique field that can be used for authentication, such as id, guid *@return string
*/
public function getAuthIdentifierName(a)
{
return $this->primaryKey;
}
/** * Get the value of the primary key *@return mixed
*/
public function getAuthIdentifier(a)
{
$id = $this- > {$this->getAuthIdentifierName()};
return $id;
}
public function getAuthPassword(a)
{
return ' ';
}
public function getRememberToken(a)
{
return ' ';
}
public function setRememberToken($value)
{
return true;
}
public function getRememberTokenName(a)
{
return ' ';
}
protected static function getBaseUri(a)
{
return config('api-host.user');
}
public static $apiMap = [
'getUserByToken'= > ['method'= >'GET'.'path'= >'login/user/token'].'getUserByGuId'= > ['method'= >'GET'.'path'= >'user/guid/:guid']];/** * Get user information (by guid) *@param string $guid
* @return User|null
*/
public static function getUserByGuId(string $guid)
{
try {
$response = self::getItem('getUserByGuId'[':guid' => $guid
]);
} catch (RestApiException $e) {
return null;
}
return $response;
}
/** * Obtain user information (by token) *@param string $token
* @return User|null
*/
public static function getUserByToken(string $token)
{
try {
$response = self::getItem('getUserByToken'['Authorization' => $token
]);
} catch (RestApiException $e) {
return null;
}
return$response; }}Copy the code
The RestApiModel above is our company’s encapsulation of the Guzzle for API calls between systems on a PHP project. I can’t tell you the code.
Guard interface
Illuminate\Contracts\Auth\Guard
The Guard interface defines an authentication method that implements the Authenticatable model or class, as well as some commonly used interfaces.
// Determine whether the current user is logged in to publicfunctioncheck(); // Check whether the current user is a tourist (not logged in) publicfunctionguest(); // Obtain the current authenticated user publicfunctionuser(); // Obtain the id of the current authenticated user, not necessarily an ID, but a unique field name (public) defined in the previous modelfunctionid(); // Authenticate user public according to the provided messagefunction validate(array $credentials= []); // Set the current user publicfunction setUser(Authenticatable $user);
Copy the code
StatefulGuard interface
Illuminate\Contracts\Auth\StatefulGuard
The StatefulGuard interface inherits from the Guard interface and adds a further, StatefulGuard in addition to some of the basic interfaces defined in Guard.
The newly added interfaces are:
// Try to verify whether the user is valid based on the provided credentials publicfunction attempt(array $credentials= [].$remember = false); // Log in once, do not record session or cookie publicfunction once(array $credentials= []); // Log in to the user and record session and cookie public after successful authenticationfunction login(Authenticatable $user.$remember = false); // Use the user ID to log in to publicfunction loginUsingId($id.$remember = false); // Use user ID to log in, but do not record session and cookie publicfunction onceUsingId($id); // Automatically log in to public using the remember token in cookiefunctionviaRemember(); / / logout publicfunction logout(a);Copy the code
Laravel provides three default guards: RequestGuard, TokenGuard, and SessionGuard.
RequestGuard
Illuminate\Auth\RequestGuard
The RequestGuard is a very simple guard. the RequestGuard is authenticated by passing in a closure. You can add a custom RequestGuard by calling Auth::viaRequest.
SessionGuard
Illuminate\Auth\SessionGuard
SessionGuard is the default Guard for Laravel Web authentication.
TokenGuard
Illuminate\Auth\TokenGuard
The TokenGuard applies to stateless API authentication and is authenticated by token.
Implementing customizationGuard
App\Auth\UserGuard.php
namespace App\Auth;
use Illuminate\Http\Request;
use Illuminate\Auth\GuardHelpers;
use Illuminate\Contracts\Auth\Guard;
use Illuminate\Contracts\Auth\UserProvider;
class UserGuard implements Guard
{
use GuardHelpers;
protected $user = null;
protected $request;
protected $provider;
/**
* The name of the query string item from the request containing the API token.
*
* @var string
*/
protected $inputKey;
/**
* The name of the token "column" in persistent storage.
*
* @var string
*/
protected $storageKey;
/**
* The user we last attempted to retrieve
* @var* /
protected $lastAttempted;
/**
* UserGuard constructor.
* @param UserProvider $provider
* @param Request $request
* @return void
*/
public function __construct(UserProvider $provider, Request $request = null)
{
$this->request = $request;
$this->provider = $provider;
$this->inputKey = 'Authorization';
$this->storageKey = 'api_token';
}
/**
* Get the currently authenticated user.
* @return \Illuminate\Contracts\Auth\Authenticatable|null
*/
public function user(a)
{
if(! is_null($this->user)) {
return $this->user;
}
$user = null;
$token = $this->getTokenForRequest();
if(!empty($token)) {
$user = $this->provider->retrieveByCredentials(
[$this->storageKey => $token]
);
}
return $this->user = $user;
}
/**
* Rules a user's credentials.
* @param array $credentials
* @return bool
*/
public function validate(array $credentials = [])
{
if (empty($credentials[$this->inputKey])) {
return false;
}
$credentials = [$this->storageKey => $credentials[$this->inputKey]];
$this->lastAttempted = $user = $this->provider->retrieveByCredentials($credentials);
return $this->hasValidCredentials($user, $credentials);
}
/**
* Determine if the user matches the credentials.
* @param mixed $user
* @param array $credentials
* @return bool
*/
protected function hasValidCredentials($user, $credentials)
{
return! is_null($user) &&$this->provider->validateCredentials($user, $credentials);
}
/**
* Get the token for the current request.
* @return string
*/
public function getTokenForRequest(a)
{
$token = $this->request->header($this->inputKey);
return $token;
}
/**
* Set the current request instance.
*
* @param \Illuminate\Http\Request $request
* @return $this
*/
public function setRequest(Request $request)
{
$this->request = $request;
return $this; }}Copy the code
Add the following code to the boot method of AppServiceProvider: App\Providers\ authServiceprovider.php
.// auth:api -> token provider.
Auth::provider('token'.function(a) {
return app(UserProvider::class);
});
// auth:api -> token guard.
// @throw \Exception
Auth::extend('token'.function($app, $name, array $config) {
if($name === 'api') {
return app()->make(UserGuard::class, [
'provider' => Auth::createUserProvider($config['provider']),
'request' => $app->request,
]);
}
throw new \Exception('This guard only serves "auth:api".'); }); .Copy the code
-
Add a custom Guard to the Guards array in config\auth.php. A custom Guard consists of two parts: driver and Provider.
-
Set defaults.guard to API in config\auth. PHP.
return [
/* |-------------------------------------------------------------------------- | Authentication Defaults |-------------------------------------------------------------------------- | | This option controls the default authentication "guard" and password | reset options for your application. You may change these defaults | as required, but they're a perfect start for most applications. | */
'defaults'= > ['guard'= >'api'.'passwords'= >'users',]./* |-------------------------------------------------------------------------- | Authentication Guards |-------------------------------------------------------------------------- | | Next, you may define every authentication guard for your application. | Of course, a great default configuration has been defined for you | here which uses session storage and the Eloquent user provider. | | All authentication drivers have a user provider. This defines how the | users are actually retrieved out of your database or other storage | mechanisms used by this application to persist your user's data. | | Supported: "session", "token" | */
'guards'= > ['web'= > ['driver'= >'session'.'provider'= >'users',].'api'= > ['driver'= >'token'.'provider'= >'token',]],/* |-------------------------------------------------------------------------- | User Providers |-------------------------------------------------------------------------- | | All authentication drivers have a user provider. This defines how the | users are actually retrieved out of your database or other storage | mechanisms used by this application to persist your user's data. | | If you have multiple user tables or models you may configure multiple | sources which represent each model / table. These sources may then | be assigned to any extra authentication guards you have defined. | | Supported: "database", "eloquent" | */
'providers'= > ['users'= > ['driver'= >'eloquent'.'model' => App\Models\User::class,
],
'token'= > ['driver'= >'token'.'model' => App\Models\User::class,
],
],
/* |-------------------------------------------------------------------------- | Resetting Passwords |-------------------------------------------------------------------------- | | You may specify multiple password reset configurations if you have more | than one user table or model in the application and you want to have | separate password reset settings based on the specific user types. | | The expire time is the number of minutes that the reset token should be | considered valid. This security feature keeps tokens short-lived so | they have less time to be guessed. You may change this as needed. | */
'passwords'= > ['users'= > ['provider'= >'users'.'table'= >'password_resets'.'expire'= >60,]]];Copy the code
Usage:
Original address reference article: Address
The first time to write so many words of the article, write bad please forgive me!!