laravel jwt实现用户认证登录

9 篇文章 0 订阅
1 篇文章 0 订阅

一、什么是jwt,怎么运行的
1、jwt == Json Web Tokens
2、传统认证与jwt认证的区别与优势:
传统的方式:
主要是将认证后的用户信息储存在服务器上,比如Session。用户下次请求的时候带上Session Id,然后服务器以此查询用户是否认证过
在这里插入图片描述
传统认证方式的问题:
(1)、每次用户认证通过后,服务器需要创建一天记录保存用户信息,通常是在内存中,随着认证通过的用户越来越多,服务器在这里的开销就越来越大
(2)、session是在内存中,容易带来一些扩展性的问题
(3)、当我们想要扩展应用,需要多个服务器提供服务时,需要考虑session共享问题,不然可能会导致用户多次登录
(4)、用户容易收到csrf攻击,且要考虑客户端禁用cookie的问题

jwt认证方式
工作流程
在这里插入图片描述
1.用户携带用户名和密码登入;
2.服务器校验用户信息
3.然后服务器提供一个token给客户端(jwt)
4.客户端会存储token,并且在随后的每一次请求中都带着它
5.服务器校验token,并获取信息。

注意的点:
1.每一次请求都需要token
2.token应该放在请求header中
3.我们还需要将服务器设置为接受来自所有域的请求,用Access-Control-Allow-Origin:*

JWT组成结构;头部、负载、签名
jwt =》这是一个字符串在字符串中通过 . 进行分割; 分为了三个部分;
第一部分;header
第二部分:payload
第三部分:signature

使用jwt的好处
1、无状态和可扩展性:token存储在客户端,完全无状态,可扩展。负载均衡器可以将用户传递到任意服务器,因为在任何地方都没有状态或回话信息
2、安全性:token不是cookie,每次请求token都会被发送,由于没有cookie,有助于防止csrf攻击
3、token在一段时间后会过期,这个时候需要重新登录,有助于保持安全,还有一个概念叫token撤销,它允许我们根据相同的授权许可使特定的token甚至一组token无效

jwt的问题
1、token失效问题:比如在浏览器端通过用户名、密码验证获得签名的token被木马窃取,即使用户登出系统,黑客还是可以利用窃取的token模拟正常请求,可用它访问服务器,而服务器端对此完全不知道,因为jwt机制是无状态的,直到过期,中间服务器无法控制它
2、app类token的有效时间:如果APP是新闻类、游戏类、聊天类等需要长时间用户粘性的,一般可设置1年的有效时间。如果是支付类、银行类的,一般token有效时间比较短,15分钟左右

所以:一般在jwt中不要放太多敏感性的词,如果需要的话那么就要加密。其次就是设置失效时间对应的得当

二、laravel中使用jwt进行认证
jwt-auth文档:https://jwt-auth.readthedocs.io/en/develop/laravel-installation/
1、jwt的安装
composer require tymon/jwt-auth
在这里插入图片描述2、发布配置
然后执行
php artisan vendor:publish --provider=“Tymon\JWTAuth\Providers\LaravelServiceProvider”
这个指令就是把jwt的配置发布出,简单点就是在config目录下创建一个jwt的配置文件,同时也把jwt的组件服务加载到项目中,之后就可以通过在env的配置中修改
在这里插入图片描述
3、生成秘钥
然后可以再运行
php artisan jwt:secret
这个命令会在env中增加一个JWT_SECRET,同我们的APP_KEY这个secret是十分重要的,用于给Token签名,更换这个secret会导致之前生成的所有token无效,所以不要随意的替换这个secret
在这里插入图片描述
4、手动添加服务提供者信息(Laravel5.4及以下版本需要,5.5及以上版本无需手动添加)
将下面这行添加至 config/app.php 文件 providers 数组中:

#文件:config/app.php
'providers' => [
    // other code
    Tymon\JWTAuth\Providers\LaravelServiceProvider::class,
]

5、配置Auth guard,让api的driver使用jwt

#文件:config/auth.php
'guards' => [
    'api' => [
        'driver' => 'jwt',
        'provider' => 'users',
    ],
],

6、更改 User Model,让User 支持 jwt-auth,并重写getJWTIdentifier()和getJWTCustomClaims()方法

<?php
namespace App\Models;


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

class Users extends Authenticatable implements JWTSubject
{
    use Notifiable ;

    protected $table = 'users';

    public function getJWTCustomClaims()
    {
        // TODO: Implement getJWTCustomClaims() method.
        return [];
    }


    public function getJWTIdentifier()
    {
        // TODO: Implement getJWTIdentifier() method.
        return $this->getKey();
    }

}

7、注册两个 Facade别名
这两个 Facade 不是必须的,但是使用它们会给你的代码编写带来一点便利。
config/app.php

#
'aliases' => [
        ...
        // 添加以下两行
       'JWTAuth' => Tymon\JWTAuth\Facades\JWTAuth::class,
       'JWTFactory' => Tymon\JWTAuth\Facades\JWTFactory::class,
],

8、注册路由和创建控制器

路由:

Route::group(['namespace' => 'Api\V1'],function (){
    Route::any('users/login','UsersController@login');
});

控制器:

<?php


namespace App\Http\Controllers\Api\V1;

use App\Models\UsersModel;
use Illuminate\Http\Request;
//use Tymon\JWTAuth\Facades\JWTAuth;
use JWTAuth;
class UsersController extends BaseController
{
    /**
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     */
    public function login(Request $request)
    {

        $data = $request->input();
        $phone = $data['phone'];
		//以手机号登录测试,具体根据自己的业务逻辑
        $user = UsersModel::where(['phone' => $phone])->first();


        if(!$user){
            $user = new UsersModel();
            $user->phone = $phone;
            $user->save();
        }


        //方式一
        $token = JWTAuth::fromUser($user);
        //方式二
//        $token = auth('api')->login($user);

        //方式三、下面这种方式必须使用密码登录
//        $token = auth('api')->attempt($user->toArray());

        if(!$token ){
            return response()->json(['error' => 'Unauthorized'],401);
        }

        return $this->respondWithToken($token,$user);


    }
    
 	protected function respondWithToken($token, $data)
    {
        return response()->json([
            'data' => $data,
            'access_token' =>'bearer '.$token,
            'token_type' => 'bearer'
        ]);
    }

}

返回结果:
在这里插入图片描述
到此用户登录生成jwt认证token完成

用户登录生成token返回前端后,每次请求都需将token随着请求头一起传递到后端,故而需要验证请求是否携带token,以及检验token是否过期,通过创建一个中间件,来对需要验证的路由进行统一验证
创建路由中间件
Middleware文加下

<?php


namespace App\Http\Middleware;

use Closure;
use Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException;
use Tymon\JWTAuth\Exceptions\JWTException;
use Tymon\JWTAuth\Exceptions\TokenExpiredException;
use Tymon\JWTAuth\Http\Middleware\BaseMiddleware;
use Auth;

class RefreshToken extends BaseMiddleware
{

    /**
     * @param $request
     * @param Closure $next
     * @return \Illuminate\Http\JsonResponse|\Illuminate\Http\Response|mixed
     * @throws JWTException
     */
    public function handle($request , Closure $next)
    {
        //检查此次请求中,是否携带token,如果没有则抛出异常
        $this->checkForToken($request);

        try{
            //检测用户登录状态,如果正常,则通过
            if($this->auth->parseToken()->authenticate()){
                return $next($request);
            }

            throw new UnauthorizedHttpException('jwt-auth',json_encode(['status' => 401,'msg' => '未登录']));

        }catch (TokenExpiredException $exception){
            
            // 此处捕获到了 token 过期所抛出的 TokenExpiredException 异常,我们在这里需要做的是刷新该用户的 token 并将它添加到响应头中
            try{
                //刷新用户token,并放到头部
                $token = $this->auth->refresh();

                //使用一次性登录,保证请求成功
                Auth::guard('api')->onceUsingId($this->auth->manager()->getPayloadFactory()->buildClaimsCollection()->toPlainArray()['sub']);

            }catch (JWTException $exception){
                //如果走到这里,说明refresh也过期了,需要重新登录

                throw new UnauthorizedHttpException('jwt-auth',json_encode(['status' => 401 , 'msg' => '未登录']));
            }
        }

        //在响应头中返回新的token

        return $this->setAuthenticationHeader($next($request),$token);


    }


}

注册新增的中间件到Kernel.php文件中的$routeMiddleware数组中

'refresh.token' => \App\Http\Middleware\RefreshToken::class,

在这里插入图片描述

创建测试路由

Route::group(['namespace' => 'Api\V1','middleware'=>'refresh.token'],function(){
    //测试是否携带token
    Route::any('users/test','UsersController@test');
});

在这里插入图片描述
在这里插入图片描述
对于使用了token验证中间件的路由,在请求时未携带token或者已过期,则会提示401 Token not provided,此时需要重新登录获取新的token,并携带新的token再次请求接口

  • 1
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值