• laravel5.5 dingo/api+jwt-auth


    因为laravel5.5 具有发现包功能,只要包做了兼容laravel5.5就可以不用在config/app.php添加额外代码了。

    集成dingo/api

    github:https://github.com/dingo/api

    添加

    "dingo/api": "2.0.0-alpha1",
    

    到项目下的composer.json文件的require配置项,然后

    composer update
    

    生成配置文件到config/api.php:

    php artisan vendor:publish --provider="DingoApiProviderLaravelServiceProvider"
    

    在.env配置文件中,设置dingo/api相关配置:

    API_STANDARDS_TREE=vnd // 环境
    API_SUBTYPE=myapp // 子类型
    API_PREFIX=api // 前缀
    API_DOMAIN=api.myapp.com //子域名  (前缀和子域名只能存在一个)
    API_VERSION=v1 // 版本
    API_NAME="My API" // 名字(使用API Blueprint命令才会用到)
    API_CONDITIONAL_REQUEST=false // 带条件的请求
    API_STRICT=false // Strict模式
    API_DEFAULT_FORMAT=json // 响应格式
    API_DEBUG=true // 调试模式
    

    注意:.env配置文件是不能有空格和注释的!

    dingo/api集成就完成

    集成jwt教程

    添加

    "tymon/jwt-auth": "^1.0.0-rc.1"
    

    到项目下的composer.json文件的require配置项,然后

    composer update
    

    然后发布微调配置文件

    php artisan vendor:publish --provider="TymonJWTAuthProvidersLaravelServiceProvider"
    

    将会在config文件夹生成jwt.php文件

    在config/jwt.php中,你可以配置以下选项:

    • ttl:token有效期(分钟)
    • refresh_ttl:刷新token时间(分钟)
    • algo:token签名算法
    • user:指向User模型的命名空间路径
    • identifier:用于从token的sub中获取用户
    • require_claims:必须出现在token的payload中的选项,否则会抛出TokenInvalidException异常
    • blacklist_enabled:如果该选项被设置为false,那么我们将不能废止token,即使我们刷新了token,前一个token仍然有效
    • providers:完成各种任务的具体实现,如果需要的话你可以重写他们
      • User —— providers.user:基于sub获取用户的实现
      • JWT —— providers.jwt:加密/解密token
      • Authentication —— providers.auth:通过证书/ID获取认证用户
      • Storage —— providers.storage:存储token直到它们失效

    然后运行:

    php artisan jwt:secret
    

    github :https://github.com/tymondesigns/jwt-auth

    jwt.php配置详解如下:

    ttl:token有效期(分钟)
    refresh_ttl:刷新token时间(分钟)
    algo:token签名算法
    user:指向User模型的命名空间路径
    identifier:用于从token的sub中获取用户
    require_claims:必须出现在token的payload中的选项,否则会抛出TokenInvalidException异常
    blacklist_enabled:如果该选项被设置为false,那么我们将不能废止token,即使我们刷新了token,前一个token仍然有效
    providers:完成各种任务的具体实现,如果需要的话你可以重写他们
    User —— providers.user:基于sub获取用户的实现
    JWT —— providers.jwt:加密/解密token
    Authentication —— providers.auth:通过证书/ID获取认证用户
    Storage —— providers.storage:存储token直到它们失效
    

    至此,jwt集成就完成了。

    创建Token

    创建用户token最常用的方式就是通过登录实现用户认证,如果成功则返回相应用户的token。这里假设我们有一个AuthenticateController

    use JWTAuth;
    use TymonJWTAuthExceptionsJWTException;
    
    class AuthenticateController extends Controller
    {
        public function authenticate(Request $request)
        {
            // grab credentials from the request
            $credentials = $request->only('email', 'password');
    
            try {
                // attempt to verify the credentials and create a token for the user
                if (! $token = JWTAuth::attempt($credentials)) {
                    return response()->json(['error' => 'invalid_credentials'], 401);
                }
            } catch (JWTException $e) {
                // something went wrong whilst attempting to encode the token
                return response()->json(['error' => 'could_not_create_token'], 500);
            }
    
            // all good so return the token
            return response()->json(compact('token'));
        }
    }
    

    有时候我们还可以直接通过用户对象实例创建token:

    // grab some user
    $user = User::first();
    $token = JWTAuth::fromUser($user);
    

    此外,还可以使用TymonJWTAuthPayloadFactory实例(或者JWTFactory门面)基于任意数据创建token:

    $customClaims = ['foo' => 'bar', 'baz' => 'bob'];
    $payload = JWTFactory::make($customClaims);
    $token = JWTAuth::encode($payload);
    

    还可以使用方法链的方式:

    // add a custom claim with a key of `foo` and a value of ['bar' => 'baz']
    $payload = JWTFactory::sub(123)->aud('foo')->foo(['bar' => 'baz'])->make();
    $token = JWTAuth::encode($payload);
    

    用户认证

    用户登录成功之后,下一步就是发送一个包含token的请求来获取用户信息。

    要通过http发送一个需要认证通过的请求,需要设置Authorization头:

    Authorization: Bearer {yourtokenhere}
    

    如果用户名/密码没有进行base64编码那么Apache似乎会摒弃Authorization头,要修复这一问题你可以添加如下代码到Apache配置文件:

    RewriteEngine On
    RewriteCond %{HTTP:Authorization} ^(.*)
    RewriteRule .* - [e=HTTP_AUTHORIZATION:%1]
    

    或者将token信息包含到URL中:

    http://api.mysite.com/me?token={yourtokenhere}

    要从请求中获取token,你可以这么做:

    // this will set the token on the object
    JWTAuth::parseToken();// and you can continue to chain methods
    $user = JWTAuth::parseToken()->authenticate();
    

    要获取该token值,你可以这么调用:

    $token = JWTAuth::getToken();
    

    如果token被设置则会返回,否则会尝试使用方法从请求中解析token,如果token未被设置或不能解析最终返回false。

    当然如果需要的话你还可以手动设置token:

    JWTAuth::setToken('foo.bar.baz');

    从Token中获取认证用户:

    // somewhere in your controller
    public function getAuthenticatedUser()
    {
        try {
            if (! $user = JWTAuth::parseToken()->authenticate()) {
                return response()->json(['user_not_found'], 404);
            }
        } catch (TymonJWTAuthExceptionsTokenExpiredException $e) {
            return response()->json(['token_expired'], $e->getStatusCode());
        } catch (TymonJWTAuthExceptionsTokenInvalidException $e) {
            return response()->json(['token_invalid'], $e->getStatusCode());
        } catch (TymonJWTAuthExceptionsJWTException $e) {
            return response()->json(['token_absent'], $e->getStatusCode());
        }
    
        // the token is valid and we have found the user via the sub claim
        return response()->json(compact('user'));
    }
    

    jwt-auth扩展还提供了两个中间件GetUserFromTokenRefreshToken,前者用于在请求头和参数中检查是否包含token,并尝试对其解码,后者会再次从请求中解析token,并顺序刷新token(同时废弃老的token)并将其作为下一个响应的一部分。要使用这两个中间件,需要到app/Http/Kernel.php下的$routeMiddleware属性中注册它们:

    protected $routeMiddleware = [
        ...
        'jwt.auth' => 'TymonJWTAuthMiddlewareGetUserFromToken',
        'jwt.refresh' => 'TymonJWTAuthMiddlewareRefreshToken',
    ];

    JWT让用户认证变得简单和安全,token会被保存到本地的storage/web或Cookie中,使用JWT,基于API的用户认证将不再困难。

    测试dingo/api 和 jwt:

    在routes/api.php文件添加:

    // 接管路由
    $api = app('DingoApiRoutingRouter');
    
    // 配置api版本和路由
    $api->version('v1', ['namespace' => 'AppHttpApiV1Controllers'], function ($api) {
    
        // 授权组
        $api->group(['prefix' => 'auth'], function ($api) {
            //$api->post('register', 'AuthenticateController@register')->name('auth.register');
    
            $api->post('register', 'AuthController@register');
            $api->post('login', 'AuthController@login');
            $api->post('logout', 'AuthController@logout');
            $api->post('refresh', 'AuthController@refresh');
            $api->post('me', 'AuthController@me');
            $api->get('test', 'AuthController@test');
        });
    
        $api->get('test/testapi', 'UserController@test')->name('test');
        $api->get('test/testjwt', 'UserController@testjwt')->name('testjwt');
        $api->get('users/{id}', 'UserController@getUserInfo')->name('getUserInfo');
    });
    
    

    文件路径:AppHttpApiV1ControllersAuthController.php

    <?php
    /**
     * Date: 17/10/12
     * Time: 01:07
     */
    
    namespace AppHttpApiV1Controllers;
    
    use IlluminateHttpRequest;
    use IlluminateSupportFacadesAuth;
    use Validator;
    use AppUser;
    
    class AuthController extends BaseController
    {
    
        protected $guard = 'api';//设置使用guard为api选项验证,请查看config/auth.php的guards设置项,重要!
    
        /**
         * Create a new AuthController instance.
         *
         * @return void
         */
        public function __construct()
        {
            $this->middleware('auth:api', ['except' => ['login','register']]);
        }
    
        public function test(){
            echo "test!!";
        }
    
        public function register(Request $request)
        {
    
            $rules = [
                'name' => ['required'],
                'email' => ['required'],
                'password' => ['required', 'min:6', 'max:16'],
            ];
    
            $payload = $request->only('name', 'email', 'password');
            $validator = Validator::make($payload, $rules);
    
            // 验证格式
            if ($validator->fails()) {
                return $this->response->array(['error' => $validator->errors()]);
            }
    
            // 创建用户
            $result = User::create([
                'name' => $payload['name'],
                'email' => $payload['email'],
                'password' => bcrypt($payload['password']),
            ]);
    
            if ($result) {
                return $this->response->array(['success' => '创建用户成功']);
            } else {
                return $this->response->array(['error' => '创建用户失败']);
            }
    
        }
    
        /**
         * Get a JWT token via given credentials.
         *
         * @param  IlluminateHttpRequest  $request
         *
         * @return IlluminateHttpJsonResponse
         */
        public function login(Request $request)
        {
            $credentials = $request->only('email', 'password');
    
            if ($token = $this->guard()->attempt($credentials)) {
                return $this->respondWithToken($token);
            }
    
            return $this->response->errorUnauthorized('登录失败');
        }
    
        /**
         * Get the authenticated User
         *
         * @return IlluminateHttpJsonResponse
         */
        public function me()
        {
            //return response()->json($this->guard()->user());
            return $this->response->array($this->guard()->user());
        }
    
        /**
         * Log the user out (Invalidate the token)
         *
         * @return IlluminateHttpJsonResponse
         */
        public function logout()
        {
            $this->guard()->logout();
    
            //return response()->json(['message' => 'Successfully logged out']);
            return $this->response->array(['message' => '退出成功']);
        }
    
        /**
         * Refresh a token.
         *
         * @return IlluminateHttpJsonResponse
         */
        public function refresh()
        {
            return $this->respondWithToken($this->guard()->refresh());
        }
    
        /**
         * Get the token array structure.
         *
         * @param  string $token
         *
         * @return IlluminateHttpJsonResponse
         */
        protected function respondWithToken($token)
        {
            return response()->json([
                'access_token' => $token,
                'token_type' => 'bearer',
                'expires_in' => $this->guard()->factory()->getTTL() * 60
            ]);
        }
    
        /**
         * Get the guard to be used during authentication.
         *
         * @return IlluminateContractsAuthGuard
         */
        public function guard()
        {
            return Auth::guard($this->guard);
        }
    }
    
    

    文件路径:AppUser.php 需要implements JWTSubject

    <?php
    
    namespace App;
    
    use TymonJWTAuthContractsJWTSubject;
    use IlluminateNotificationsNotifiable;
    use IlluminateFoundationAuthUser as Authenticatable;
    
    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',
        ];
    
    
        // Rest omitted for brevity
    
        /**
         * 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 [];
        }
    }
    

    记得要在config/auth.php修改

    //设置默认使用的guard,此处设置为api时,laravel 默认的auth登录则无法登录成功哦,设置为web才行
        'defaults' => [
            'guard' => 'web',
            'passwords' => 'users',
        ],
    
        'guards' => [
            'web' => [
                'driver' => 'session',
                'provider' => 'users',
            ],
    
            'api' => [
                'driver' => 'jwt',
                'provider' => 'users',
            ],
        ],
    

    好了自己慢慢消化,我也是经历很久的测试才得出的结果,未经允许请勿转载!

    参考:https://github.com/tymondesigns/jwt-auth/blob/docs/docs/quick-start.md
    参考:https://github.com/tymondesigns/jwt-auth/issues/1316
    参考:https://moell.cn/article/37



    作者:HaRun
    链接:https://www.jianshu.com/p/62b0c4d75e59
    來源:简书
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
  • 相关阅读:
    技术选型总结
    这些年来收集的好用的好玩的软件,强烈推荐给大家
    如何解决markdown中图片上传的问题
    01.如何把.py文件打包成为exe,重点讲解pyinstaller的用法
    Asp.net中汉字转换成为拼音
    程序员常用网址收集
    通过IP来判断所在城市
    以太坊
    分布式系统领域经典论文翻译集
    T50
  • 原文地址:https://www.cnblogs.com/grimm/p/8526799.html
Copyright © 2020-2023  润新知