Lumen企业站内容管理实战 - 后台管理之认证一

后台管理之认证

前边我们把验证码做好了,这章我介绍下登录的认证,我介绍的认证是基于jwt的

首先在composer.json文件中加入

"require": {
        "tymon/jwt-auth": "^1.0.0-rc.1"
    },

然后执行命令

composer updsate

Lumen企业站内容管理实战 - 后台管理之认证一_第1张图片

 然后打开/bootstrap/app.php文件加入

$app->register(Tymon\JWTAuth\Providers\LumenServiceProvider::class);

Lumen企业站内容管理实战 - 后台管理之认证一_第2张图片

 然后生成秘钥

php artisan jwt:secret

打开.evn文件,你能看到新出现了秘钥

JWT_SECRET=QjQJCJhSR6OslcctlI1E0dtGOESSx5fJ1fYShzvLyRkFymFjciqzavaXpNtthdJ1

 然后打开管理员模型/app/Models/Admin.php文件,让Admin类实现三个接口。一下代码是新增的,因为我们模型中已经有其他方法了,为了简洁,我贴出来了新增的代码。

AuthenticatableContract, AuthorizableContract, JWTSubject
getKey();
    }

    /**
     * Return a key value array, containing any custom claims to be added to the JWT.
     *
     * @return array
     */
    public function getJWTCustomClaims()
    {
        return [];
    }


}

然后把/vendor/laravel/lumne-framework/目录下的config目录复制到项目目录下

Lumen企业站内容管理实战 - 后台管理之认证一_第3张图片

打开auth.php文件,要修改几个地方

// 修改前
'defaults' => [
        'guard' => env('AUTH_GUARD', 'api'),
    ],

// 替换成下边样子。这个认证是对应后台管理的,我就使用admin了
'defaults' => [
        'guard' => env('AUTH_GUARD', 'admin'),
    ],
//替换前
'guards' => [
        'api' => ['driver' => 'api'],
    ],

//替换后台。这里的admin要对应到前边guard的admin
'guards' => [
        'admin' => [
            'driver' => 'jwt', // 使用jwt
            'provider' => 'admins'
        ],
    ],
//修改前
'providers' => [
        //
    ],
// 修改后。
'providers' => [
        'admins' => [
            'driver' => 'eloquent',
            'model' => \App\Models\Admin::class, //管理员模型
        ],
    ],

最终代码

 [
        'guard' => env('AUTH_GUARD', 'admin'),
    ],

    /*
    |--------------------------------------------------------------------------
    | 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: "token"
    |
    */

    'guards' => [
        'admin' => [
            'driver' => 'jwt',
            'provider' => 'admins'
        ],
    ],

    /*
    |--------------------------------------------------------------------------
    | 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' => [
        'admins' => [
            'driver' => 'eloquent',
            'model' => \App\Models\Admin::class,
        ],
    ],

    /*
    |--------------------------------------------------------------------------
    | Resetting Passwords
    |--------------------------------------------------------------------------
    |
    | Here you may set the options for resetting passwords including the view
    | that is your password reset e-mail. You may also set the name of the
    | table that maintains all of the reset tokens for your application.
    |
    | 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' => [
        //
    ],

];

配置结束,接下来开始老流程,路由、模型、控制器

路由

$router->post('/admin/login', 'AdminAuthController@login');
$router->post('/admin/logout', 'AdminAuthController@logout');

Lumen企业站内容管理实战 - 后台管理之认证一_第4张图片

打开 Admin模型

 

然后建立一个AdminAuthController.php文件,这个文件我们建立在Controller目录下

jwt = $jwt;
    }

    public function login(Request $request)
    {
        // 验证提交的数据
        $this->validate($request, [
            'user_name' => 'required|string|max:20|min:2',
            'password' => 'required|string|max:16|min:6',
            'vercode' => 'required|max:4|min:4',
        ]);

        // 接收提交的数据
        $userName = $request->input('user_name');
        $password = $request->input('password');
        $vercode = $request->input('vercode');

        // 取出服务器端保存的验证码
        $captchaCode = $_COOKIE['captcha'] ?? '';

        // 验证验证码是否一致,不一致直接返回错误
        if (app('captcha')->check($vercode, $captchaCode) === false) {
            $this->response->setMsg(400, '验证码错误');
            return $this->response->responseJSON();
        }

        // 验证码使用完后,消除cookie,为了安全
        setcookie('captcha',$vercode,time() - 10);

        $admin = Admin::where('user_name', $userName)->first();

        // 如果用户名不存在,直接返回错误
        if (empty($admin->id)) {
            $this->response->setMsg(400, '账号或者密码错误');
            return $this->response->responseJSON();
        }

        // 检查密码是否一致,不一致的话,返回错误
        if (!password_verify($password, $admin->password)) {
            $this->response->setMsg(400, '账号或者密码错误');
            return $this->response->responseJSON();
        }

        // 账号未启用,不能登录
        if ($admin->state != 1) {
            $this->response->setMsg(-1, '错误!请联系管理员');
            return $this->response->responseJSON();
        }

        $token = $this->jwt->fromUser($admin); // 获取token
        $data = $this->respondWithToken($token); // 组装相关信息

        $this->response->setData($data);
        return $this->response->responseJSON();


    }

    public function logout(Request $request)
    {

    }

    protected function respondWithToken($token)
    {
        return [
            'access_token' => $token,
            'token_type' => 'bearer',
            'expires_in' => $this->jwt->factory()->getTTL(),
        ];
    }
}

我们用postman请求下接口看看通不通

Lumen企业站内容管理实战 - 后台管理之认证一_第5张图片

接口通了,但是返回user_name字段是必填的,这个也正确,因为我们没有提交user_name信息,我们把信息补全

Lumen企业站内容管理实战 - 后台管理之认证一_第6张图片

我得请求验证码接口,拿到验证码 

Lumen企业站内容管理实战 - 后台管理之认证一_第7张图片

 我把data中的那一长串字符复制出来,然后找个页面

Lumen企业站内容管理实战 - 后台管理之认证一_第8张图片

src后边的值就是我复制出来的,然后看看验证码

Lumen企业站内容管理实战 - 后台管理之认证一_第9张图片

我们回到postman,修改下参数

Lumen企业站内容管理实战 - 后台管理之认证一_第10张图片

access_token的值就是生成的token,还有过期时间expires_in,值是60分钟,如何修改这个值呢?在config目录下新建一个文件jwt.php,


 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

return [

    /*
    |--------------------------------------------------------------------------
    | JWT Authentication Secret
    |--------------------------------------------------------------------------
    |
    | Don't forget to set this in your .env file, as it will be used to sign
    | your tokens. A helper command is provided for this:
    | `php artisan jwt:secret`
    |
    | Note: This will be used for Symmetric algorithms only (HMAC),
    | since RSA and ECDSA use a private/public key combo (See below).
    |
    */

    'secret' => env('JWT_SECRET'),

    /*
    |--------------------------------------------------------------------------
    | JWT Authentication Keys
    |--------------------------------------------------------------------------
    |
    | The algorithm you are using, will determine whether your tokens are
    | signed with a random string (defined in `JWT_SECRET`) or using the
    | following public & private keys.
    |
    | Symmetric Algorithms:
    | HS256, HS384 & HS512 will use `JWT_SECRET`.
    |
    | Asymmetric Algorithms:
    | RS256, RS384 & RS512 / ES256, ES384 & ES512 will use the keys below.
    |
    */

    'keys' => [

        /*
        |--------------------------------------------------------------------------
        | Public Key
        |--------------------------------------------------------------------------
        |
        | A path or resource to your public key.
        |
        | E.g. 'file://path/to/public/key'
        |
        */

        'public' => env('JWT_PUBLIC_KEY'),

        /*
        |--------------------------------------------------------------------------
        | Private Key
        |--------------------------------------------------------------------------
        |
        | A path or resource to your private key.
        |
        | E.g. 'file://path/to/private/key'
        |
        */

        'private' => env('JWT_PRIVATE_KEY'),

        /*
        |--------------------------------------------------------------------------
        | Passphrase
        |--------------------------------------------------------------------------
        |
        | The passphrase for your private key. Can be null if none set.
        |
        */

        'passphrase' => env('JWT_PASSPHRASE'),

    ],

    /*
    |--------------------------------------------------------------------------
    | JWT time to live
    |--------------------------------------------------------------------------
    |
    | Specify the length of time (in minutes) that the token will be valid for.
    | Defaults to 1 hour.
    |
    | You can also set this to null, to yield a never expiring token.
    | Some people may want this behaviour for e.g. a mobile app.
    | This is not particularly recommended, so make sure you have appropriate
    | systems in place to revoke the token if necessary.
    |
    */

    'ttl' => env('JWT_TTL', 7200),

    /*
    |--------------------------------------------------------------------------
    | Refresh time to live
    |--------------------------------------------------------------------------
    |
    | Specify the length of time (in minutes) that the token can be refreshed
    | within. I.E. The user can refresh their token within a 2 week window of
    | the original token being created until they must re-authenticate.
    | Defaults to 2 weeks.
    |
    | You can also set this to null, to yield an infinite refresh time.
    | Some may want this instead of never expiring tokens for e.g. a mobile app.
    | This is not particularly recommended, so make sure you have appropriate
    | systems in place to revoke the token if necessary.
    |
    */

//    'refresh_ttl' => env('JWT_REFRESH_TTL', 20160),
    'refresh_ttl' => env('JWT_REFRESH_TTL', 20160),

    /*
    |--------------------------------------------------------------------------
    | JWT hashing algorithm
    |--------------------------------------------------------------------------
    |
    | Specify the hashing algorithm that will be used to sign the token.
    |
    | See here: https://github.com/namshi/jose/tree/master/src/Namshi/JOSE/Signer/OpenSSL
    | for possible values.
    |
    */

    'algo' => env('JWT_ALGO', 'HS256'),

    /*
    |--------------------------------------------------------------------------
    | Required Claims
    |--------------------------------------------------------------------------
    |
    | Specify the required claims that must exist in any token.
    | A TokenInvalidException will be thrown if any of these claims are not
    | present in the payload.
    |
    */

    'required_claims' => [
        'iss',
        'iat',
        'exp',
        'nbf',
        'sub',
        'jti',
    ],

    /*
    |--------------------------------------------------------------------------
    | Persistent Claims
    |--------------------------------------------------------------------------
    |
    | Specify the claim keys to be persisted when refreshing a token.
    | `sub` and `iat` will automatically be persisted, in
    | addition to the these claims.
    |
    | Note: If a claim does not exist then it will be ignored.
    |
    */

    'persistent_claims' => [
        // 'foo',
        // 'bar',
    ],

    /*
    |--------------------------------------------------------------------------
    | Lock Subject
    |--------------------------------------------------------------------------
    |
    | This will determine whether a `prv` claim is automatically added to
    | the token. The purpose of this is to ensure that if you have multiple
    | authentication models e.g. `App\User` & `App\OtherPerson`, then we
    | should prevent one authentication request from impersonating another,
    | if 2 tokens happen to have the same id across the 2 different models.
    |
    | Under specific circumstances, you may want to disable this behaviour
    | e.g. if you only have one authentication model, then you would save
    | a little on token size.
    |
    */

    'lock_subject' => true,

    /*
    |--------------------------------------------------------------------------
    | Leeway
    |--------------------------------------------------------------------------
    |
    | This property gives the jwt timestamp claims some "leeway".
    | Meaning that if you have any unavoidable slight clock skew on
    | any of your servers then this will afford you some level of cushioning.
    |
    | This applies to the claims `iat`, `nbf` and `exp`.
    |
    | Specify in seconds - only if you know you need it.
    |
    */

    'leeway' => env('JWT_LEEWAY', 0),

    /*
    |--------------------------------------------------------------------------
    | Blacklist Enabled
    |--------------------------------------------------------------------------
    |
    | In order to invalidate tokens, you must have the blacklist enabled.
    | If you do not want or need this functionality, then set this to false.
    |
    */

    'blacklist_enabled' => env('JWT_BLACKLIST_ENABLED', true),

    /*
    | -------------------------------------------------------------------------
    | Blacklist Grace Period
    | -------------------------------------------------------------------------
    |
    | When multiple concurrent requests are made with the same JWT,
    | it is possible that some of them fail, due to token regeneration
    | on every request.
    |
    | Set grace period in seconds to prevent parallel request failure.
    |
    */

    'blacklist_grace_period' => env('JWT_BLACKLIST_GRACE_PERIOD', 0),

    /*
    |--------------------------------------------------------------------------
    | Cookies encryption
    |--------------------------------------------------------------------------
    |
    | By default Laravel encrypt cookies for security reason.
    | If you decide to not decrypt cookies, you will have to configure Laravel
    | to not encrypt your cookie token by adding its name into the $except
    | array available in the middleware "EncryptCookies" provided by Laravel.
    | see https://laravel.com/docs/master/responses#cookies-and-encryption
    | for details.
    |
    | Set it to true if you want to decrypt cookies.
    |
    */

    'decrypt_cookies' => false,

    /*
    |--------------------------------------------------------------------------
    | Providers
    |--------------------------------------------------------------------------
    |
    | Specify the various providers used throughout the package.
    |
    */

    'providers' => [

        /*
        |--------------------------------------------------------------------------
        | JWT Provider
        |--------------------------------------------------------------------------
        |
        | Specify the provider that is used to create and decode the tokens.
        |
        */

        'jwt' => Tymon\JWTAuth\Providers\JWT\Lcobucci::class,

        /*
        |--------------------------------------------------------------------------
        | Authentication Provider
        |--------------------------------------------------------------------------
        |
        | Specify the provider that is used to authenticate users.
        |
        */

        'auth' => Tymon\JWTAuth\Providers\Auth\Illuminate::class,

        /*
        |--------------------------------------------------------------------------
        | Storage Provider
        |--------------------------------------------------------------------------
        |
        | Specify the provider that is used to store tokens in the blacklist.
        |
        */

        'storage' => Tymon\JWTAuth\Providers\Storage\Illuminate::class,

    ],

];

找到ttl那一项,我这里改为7200分钟,在用postman登录一下看看结果

{
    "code": 200,
    "msg": "操作成功",
    "data": {
        "access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwOlwvXC9jb2NvY21zLmNvbVwvYWRtaW5cL2xvZ2luIiwiaWF0IjoxNTc5MjMzMzU3LCJleHAiOjE1Nzk2NjUzNTcsIm5iZiI6MTU3OTIzMzM1NywianRpIjoieFQ0OG1rc29hVXpxZlR3dyIsInN1YiI6MiwicHJ2IjoiZGY4ODNkYjk3YmQwNWVmOGZmODUwODJkNjg2YzQ1ZTgzMmU1OTNhOSJ9.RgTZ3LTecUv3x80OIC4gB3IwB-S0qDu5bANyJ35_djo",
        "token_type": "bearer",
        "expires_in": 7200
    }
}

我们来看看这个access_token怎么用,回到我们的/routes/web.php中,我们在$router->group()中添加中间件:'middleware' => 'auth.admin',如下

Lumen企业站内容管理实战 - 后台管理之认证一_第11张图片

这个就是对该分组下的所有路由都进行认证,所以$router->get('/login', 'AuthController@login'); /这行代码要放到分组的外边

Lumen企业站内容管理实战 - 后台管理之认证一_第12张图片

 我们找到些中间件的地方,打开/app/Http/Middleware/目录,新建AdminAuthenticate.php文件

auth = $auth;
    }

    /**
     * Handle an incoming request.
     *
     * @param \Illuminate\Http\Request $request
     * @param \Closure $next
     * @param string|null $guard
     * @return mixed
     */
    public function handle($request, Closure $next, $guard = 'admin')
    {
        $this->auth->shouldUse($guard);

        if ($this->auth->guard($guard)->guest()) {
            $arrayResult['code'] = 401;
            $arrayResult['message'] = '认证错误';
            $arrayResult['data'] = [];

            return response()->json($arrayResult, 401)->setEncodingOptions(JSON_UNESCAPED_UNICODE);
        }

        return $next($request);
    }
}

注意:handle()方法中的参数$guatd是admin,不能是其他的,这里的admin对应路由中的'middleware' => 'auth.admin',也对应/config/auth.php文件中的admin。

还没有完,打开/bootstrap/app.php文件,加入一下代码

// 此处的auth.admin对应路由中的auth.admin,不然不会生效 
$app->routeMiddleware([
     'auth.admin' => App\Http\Middleware\AdminAuthenticate::class,
 ]);

Lumen企业站内容管理实战 - 后台管理之认证一_第13张图片

我们再刷新后台管理的页面

Lumen企业站内容管理实战 - 后台管理之认证一_第14张图片

认证生效了,如何能访问呢?前边我们生成的access_token你还记得吗?我们使用这个token,使用简单的方式请求一下,在/admin/index后边加上?token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwOlwvXC9jb2NvY21zLmNvbVwvYWRtaW5cL2xvZ2luIiwiaWF0IjoxNTc5MjMzMzU3LCJleHAiOjE1Nzk2NjUzNTcsIm5iZiI6MTU3OTIzMzM1NywianRpIjoieFQ0OG1rc29hVXpxZlR3dyIsInN1YiI6MiwicHJ2IjoiZGY4ODNkYjk3YmQwNWVmOGZmODUwODJkNjg2YzQ1ZTgzMmU1OTNhOSJ9.RgTZ3LTecUv3x80OIC4gB3IwB-S0qDu5bANyJ35_djo,

即/admin/index?token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwOlwvXC9jb2NvY21zLmNvbVwvYWRtaW5cL2xvZ2luIiwiaWF0IjoxNTc5MjMzMzU3LCJleHAiOjE1Nzk2NjUzNTcsIm5iZiI6MTU3OTIzMzM1NywianRpIjoieFQ0OG1rc29hVXpxZlR3dyIsInN1YiI6MiwicHJ2IjoiZGY4ODNkYjk3YmQwNWVmOGZmODUwODJkNjg2YzQ1ZTgzMmU1OTNhOSJ9.RgTZ3LTecUv3x80OIC4gB3IwB-S0qDu5bANyJ35_djo

Lumen企业站内容管理实战 - 后台管理之认证一_第15张图片

 加上token进来了,但是管理员列表出现错误了,这个正常,因为管理员列表的url后边没有跟token,url后没有跟token的,都会出现认证错误。在前后端分离的情况下,token可以放到header中,但是,url直接请求只能跟在url后边。

JWT是服务于接口的无状态的请求的,但是我们使用的是x-admin后台管理框架,这个框架是基于iframe实现的。以上的做法,完全适用于前后端完全分离的情况,下一节我介绍如何实现登录认证,还是基于JWT方式,不过我们要换一种方法实现。

完。

你可能感兴趣的:(lumen教程)