Jwt-auth official document address

knowledge

  • Install the configurationjwt-auth
  • Request validation class decouple controller parameter validation
  • APIResource Applications

Install the configuration

Configure Composer Ali cloud mirroring

Global configuration, run the command

composer config -g repo.packagist composer https://mirrors.aliyun.com/composer/
Copy the code

To modify only the current project configuration, go to the ant-Qa-server project root directory and run the command

composer config repo.packagist composer https://mirrors.aliyun.com/composer/
Copy the code
Install using Composer

Go to the ant-Qa-server project root directory

  1. Execute the commandcomposer require tymon/jwt-authThe installation package
  2. Execute the commandphp artisan vendor:publish --provider="Tymon\JWTAuth\Providers\LaravelServiceProvider"To generate thejwtThe configuration fileconfig/jwt.php
  3. Execute the commandphp artisan jwt:secretGenerate encryption keys and add or update them.envFile,JWT_SECRET=c9wWs2aiDSKNUGX6lyrocQctrq3ON8tc7bWQDY2oyLf6G0LH8py8vuHVi9m6jRP4content

Updating the User model

Modify the app/ user.php model as follows


      

namespace App;

use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Tymon\JWTAuth\Contracts\JWTSubject;

class User extends Authenticatable implements JWTSubject
{
    use Notifiable;

    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = [
        'name'.'email'.'password',];/**
     * The attributes that should be hidden for arrays.
     *
     * @var array
     */
    protected $hidden = [
        'password'.'remember_token',];/**
     * The attributes that should be cast to native types.
     *
     * @var array
     */
    protected $casts = [
        'email_verified_at'= >'datetime',];/**
     * Get the identifier that will be stored in the subject claim of the JWT.
     *
     * @return mixed
     */
    public function getJWTIdentifier()
    {
        return $this->getKey();
    }

    /**
     * Return a key value array, containing any custom claims to be added to the JWT.
     *
     * @return array
     */
    public function getJWTCustomClaims()
    {
        return[]; }}Copy the code
Modify theconfig/auth.phpThe configuration file
'defaults'= > ['guard'= >'api'.'passwords'= >'users',].'guards'= > ['web'= > ['driver'= >'session'.'provider'= >'users',].'api'= > ['driver'= >'jwt'.'provider'= >'users'.'hash'= >false,]],Copy the code

Registered routing

Edit the routes/api.php routing file


      

Route::post('auth/login'.'AuthController@login');
Route::post('auth/register'.'AuthController@register');

// Authentication is required for access
Route::group(['middleware'= >'auth:api'].function () {
    Route::post('user/logout'.'AuthController@logout');
	  Route::get('user/info'.'UserController@find');
});
Copy the code

Routes in this file have API prefixes by default. This is the app/will/RouteServiceProvider service provider’s control

protected function mapApiRoutes()
{
    Route::prefix('api')
            ->middleware('api')
            ->namespace($this->namespace)
            ->group(base_path('routes/api.php'));
}
Copy the code

Subsequently, the controllers of API route mapping are uniformly deployed under the API directory under the control, so it is ok to modify the namespace here and join the \ API directory

protected function mapApiRoutes()
{
    Route::prefix('api')
            ->middleware('api')
						->namespace($this->namespace.'\Api')
            ->group(base_path('routes/api.php'));
}
Copy the code
createAuthControllerThe controller

Execute the command in the project root directory PHP artisan make: controller Api/AuthController, this command will create Http/app/Controllers/Api/AuthController controller, if there is no Api catalogue, It is automatically created. Next, the interface functions of registering, logging in and logging out are realized in this controller.

Registered interface

When submitting a registration request, you need to send the user name, email address, password and confirm password parameters. These parameters need to be validated when processing a registration request, and the validation logic for these parameters is written in a separate form request class.

To create a registration request class, run the artisan command

php artisan make:request RegisterRequest

After the execution, will be generated in the project file/app/Http Requests/RegisterRequest PHP file. If the Requests directory did not exist before, it will be created automatically. The initial code is as follows


      

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

class RegisterRequest extends FormRequest
{
    /**
     * Determine if the user is authorized to make this request.
     *
     * @return bool
     */
    public function authorize()
    {
        return false;
    }

    /**
     * Get the validation rules that apply to the request.
     *
     * @return array
     */
    public function rules()
    {
        return [
            //]; }}Copy the code

The authorize() method is used to check the user’s permissions. If false is returned, the user has no right to submit the form, and the permission exception is thrown to abort the request. Now we adjust it to return true


      

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

class RegisterRequest extends FormRequest
{
    /**
     * Determine if the user is authorized to make this request.
     *
     * @return bool
     */
    public function authorize()
    {
        return true;
    }

    /**
     * Get the validation rules that apply to the request.
     *
     * @return array
     */
    public function rules()
    {
        return [
            'name'= > ['required'.'string'.'max:255'].'email'= > ['required'.'string'.'email'.'max:255'.'unique:users'].'password'= > ['required'.'string'.'min:6'.'confirmed']]; }public function messages()
    {
        return [
            'name.required'= >'Name field cannot be empty'.'name.string'= >'Name field only supports strings'.'name.max'= >'Maximum name field length is 255'.'email.required'= >'Mailbox field cannot be empty'.'email.email'= >'Mailbox field must be a formatted email address'.'email.max'= >'Maximum mailbox field length is 255'.'email.unique'= >'This mailbox already exists'.// Automatically query the users table to determine whether the mailbox already exists
            'password.required'= >'Password field cannot be empty'.'password.string'= >'Password field only supports strings'.'password.min'= >'Password field length must not be less than 6'.'password.confirmed'= >'Inconsistent passwords'.// The form parameter must contain the password_confirmation field, which is the same as the password]; }}Copy the code

Next, in the AuthController controller, introduce the RegisterRequest form request class

    public function register(RegisterRequest $request)
    {
        $data = $request->all();

        $user = User::create([
            'name'= >$data['name'].'email'= >$data['email'].'password' => Hash::make($data['password']),]);$token = auth()->login($user);

        return [
            'code'= >0.'msg'= >'success'.'data'= > ['token'= >$token,]]; }Copy the code

There is no need to write form parameter validation code in this method, which is already implemented in RegisterRequest. This logic simply executes the registration code and returns the user token.

Test registration interface

The validate method verifies whether the request is an Ajax request, that is, whether the accepted data type is specified in the request header. If it is not specified, it is automatically redirected. If it is specified, for example, accept => application/json accepts JSON data. A piece of JSON data will be returned

{
    "message": "The given data was invalid."."errors": {
        "name": [
            "Name field cannot be empty"]."email": [
            "Mailbox field cannot be empty"]."password": [
            "Password field cannot be empty"]}}Copy the code

But this period of the json data does not accord with our API interface specification, you can change the app/Exception Handler. PHP files render () method, modified as follows

    public function render($request.Exception $exception)
    {
        if ($exception instanceof ValidationException) {
            $errors = $exception->errors();
            $msg = 'Parameter error';
            foreach ($errors as $errorMsg) {
                $msg = $errorMsg[0]????'Parameter error';
            }

            return response()->json([
                'code'= > -1.'msg'= >$msg.'data'= > []]); }return response()->json([
            'code'= > -1.'msg'= >'System exception'.'data'= > []]);// return parent::render($request, $exception);
    }
Copy the code

If the parameter rule is abnormal, only the first error message is obtained. Otherwise, an error message is returned

Currently, other exceptions are returned to the system exception.

Request type if we want, without judgment, unified returns json data, rather than the redirect page, you can change the Http/Middleware/app/Authenticate. PHP Middleware, modify redirectTo function as follows

use Illuminate\Auth\AuthenticationException;

protected function redirectTo($request)
{
    throw new AuthenticationException();
    if (!$request->expectsJson()) {
		    return route('login'); }}Copy the code

Normal result example

{
    "code": 0."msg": "success"."data": {
        "token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwOlwvXC9sb2NhbGhvc3RcL2FwaVwvYXV0aFwvcmVnaXN0ZXIiLCJpYXQiOjE2MDgwMD A0OTQsImV4cCI6MTYwODAwNDA5NCwibmJmIjoxNjA4MDAwNDk0LCJqdGkiOiI4OHBDeHNNV2x6R0hlRUlwIiwic3ViIjoxLCJwcnYiOiI4N2UwYWYxZWY5Zm QxNTgxMmZkZWM5NzE1M2ExNGUwYjA0NzU0NmFhIn0.PhJ50lStyG6jcVuP0uQHVSXn27uuPveL-AJZ7Lz8tL0"}}Copy the code
Login interface
The request class that defines the login interface

Run the artisan command in the project root directory

php artisan make:request LoginRequest
Copy the code

After the execution, will be generated in the project file/app/Http Requests/LoginRequest PHP file. Modify this file


      

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

class LoginRequest extends FormRequest
{
    /**
     * Determine if the user is authorized to make this request.
     *
     * @return bool
     */
    public function authorize()
    {
        return true;
    }

    /**
     * Get the validation rules that apply to the request.
     *
     * @return array
     */
    public function rules()
    {
        return [
            'email'= > ['required'.'string'.'email'.'max:255'].'password'= > ['required'.'string'.'min:6']]; }}Copy the code

Edit Http/app/Controller/Api/AuthController PHP Controller, add the login method, as follows

    public function login(LoginRequest $request)
    {
        if (!$token = auth()->attempt($request->all(['email'.'password'))) {return [
                'code'= > -1.'msg'= >'Wrong account password'.'data'= > []]; }return [
            'code'= >0.'msg'= >'success'.'data'= > ['token'= >$token,]]; }Copy the code
Logging out interface

Exit the login interface. You only need to set the token to invalid. Edit Http/app/Controller/Api/AuthController PHP Controller, add logout method, as follows

    public function logout()
    {
        auth()->logout();

        return [
            'code'= >0.'msg'= >'success'.'data'= > []]; }Copy the code

If we have direct access to http://localhost/api/user/logout interface, returns the following result

{"code": -1, "data": []}Copy the code

AuthenticationException thrown by auth: API middleware routing protection. A special code value should be specified for such exceptions so that the front end can determine whether to jump to the login page. Modify the file/Exceptions/app/Http Handler. PHP render () method

    public function render($request.Exception $exception)
    {
        if ($exception instanceof ValidationException) {
            $errors = $exception->errors();
            $msg = 'Parameter error';
            foreach ($errors as $errorMsg) {
                $msg = $errorMsg[0]????'Parameter error';
            }

            return response()->json([
                'code'= > -1.'msg'= >$msg.'data'= > []]); }if ($exception instanceof AuthenticationException) {
            return response()->json([
                'code'= > -10001.'msg'= >'Authentication failed'.'data'= > []]); } dd($exception);

        return response()->json([
            'code'= > -1.'msg'= >'System exception'.'data'= > []]);// return parent::render($request, $exception);
    }
Copy the code

Add if judgment

if ($exception instanceof AuthenticationException) {
    return response()->json([
        'code'= > -10001.'msg'= >'Authentication failed'.'data'= > []]); }Copy the code

If the exception type is AuthenticationException, the code value -10001 is returned, indicating that the authentication fails.

To access routes protected by auth: API middleware, add content to the header of the request

Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwOlwvXC9sb2NhbGhvc3RcL2FwaVwvYXV0aFwvbG9naW4iLCJpYXQiOjE2MDgwNDM1NDk sImV4cCI6MTYwODA0NzE0OSwibmJmIjoxNjA4MDQzNTQ5LCJqdGkiOiJIMVYyVk15dFY0akowUEIzIiwic3ViIjoxLCJwcnYiOiI4N2UwYWYxZWY5ZmQxNTg xMmZkZWM5NzE1M2ExNGUwYjA0NzU0NmFhIn0.nG7Hk0gMV6F5x4wmR2241PZ2jx6fFMmWghSwHajn07QCopy the code

The token can be obtained through the login interface.

Test exit login interface

The first time the token is invoked to exit the login interface, success is returned

{
    "code": 0."msg": "success"."data": []}Copy the code

If an authentication failure result is returned after sending a request to invoke the logout interface

{
    "code": - 10001.."msg": "Authentication failed"."data": []}Copy the code

Auth ()->logout(); The token has been invalidated and cannot be used again.

Interface to get user information

Interface to get user information, edited in a new UserController

php artisan make:controller Api/UserController

In the generated Http/Api/app/UserController. PHP controller, add the find method


      

namespace App\Http\Controllers\Api;

use App\Http\Controllers\Controller;
use App\Http\Resources\User;

class UserController extends Controller
{
    public function find()
    {
        $user = auth()->user();

        return [
            'code'= >0.'msg'= >'success'.'data'= > ['user'= >new User($user),]]; }}Copy the code

$user = auth()->user(); Gets the current user model based on the current logon status

The User class instantiated by new User($User) is an API resource class that performs a layer of formatting conversion between retrieved data and returned API interface data. It is also easy to reuse with subsequent places that need the same data structure.

Generate a user information resource class

Execute the command in the project root directory PHP artisan make: the resource User, generates Http/app/Resources/User. The PHP file, the initial content is as follows


      

namespace App\Http\Resources;

use Illuminate\Http\Resources\Json\JsonResource;

class User extends JsonResource
{
    /**
     * Transform the resource into an array.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return array
     */
    public function toArray($request)
    {
        return parent::toArray($request); }}Copy the code

Modify the returned user information structure. The edited content is as follows


      

namespace App\Http\Resources;

use Illuminate\Http\Resources\Json\JsonResource;

class User extends JsonResource
{
    /**
     * Transform the resource into an array.
     *
     * @param \Illuminate\Http\Request $request
     *
     * @return array
     */
    public function toArray($request)
    {
        return [
            'id'= >$this->id,
            'name'= >$this->name, ]; }}Copy the code