Laravel 5.2 使用 JWT 完成多用户认证
2017-05-03 10:49
691 查看
JWT代表Json Web Token.JWT能有效地进行身份验证并连接前后端。
降地耦合性,取代session,进一步实现前后端分离
减少服务器的压力
可以很简单的实现单点登录
我在实现这个功能的时候查到了这个扩展“tymon/jwt-auth”,最新稳定版是0.5.9。OK照着wiki撸起来,第一步我们先实现API
安装扩展#
之后打开config/app.php文件添加service provider 和 aliase
config/app.php#
OK,现在来发布JWT的配置文件,比如令牌到期时间配置等
最后一步需要生成JWT Key
创建API路由#
我在创建Api路由的时候会用到一个“cors”中间件,虽然它不是强制性的,但是后面你会发现报类似这样的错
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource athttp://xxx.com/api/register. (Reason: CORS header 'Access-Control-Allow-Origin' missing)
大致翻译下,“跨源请求阻塞:同源策略不允许读取http://kylesean.com/api/register远程资源。(原因:CORS 头“Access-Control-Allow-Origin” 没有)。” 这就是跨域请求导致的错误消息,当然你可以自定义Header,Origin, Method来解决跨域问题,不过我这边推荐一个package:barryvdh/laravel-cors(最新稳定版是0.8.2),这里安装过程省略。
创建中间件#
进入app/Http/Middleware,编辑CORS.php
app/Http/Middleware/CORS.php#
Ok,在app/Http/Kernel.php注册中间件
app/Http/Kernel.php#
有了这个中间件我们就解决了跨域问题。接下来回到路由
app/Http/routes.php#
建议:过滤掉路由api/*下的csrf_token,方便测试开发#
上面的jwt-auth中间件现在还是无效的,接着创建这个middleware
同样的我们需要编辑下这个authJWT.php
app/Http/Middleware/authJWT.php#
OK,接着注册该中间件
app/Http/Kernel.php#
然后,我们创建控制器管理所有的请求
app/Http/Controllers/ApiController.php#
最后一步我们就来模拟一个请求来测试这个api,为了模拟本地跨域请求,我们简单的新建一个静态页面test.html
这里我们要注意一下,以上测试我们仍是基于User table的,我们来模拟一下login过程,如果账号密码匹配成功,不出意外将会出现类似:
至此,我们已经实现了jwt的认证功能,那么我们接着完成下一半工作,实现jwt的多用户认证,即Jwt for Multi Auth.
如果你的业务场景是的确需要多用户认证,比如为管理员admin单独生成一张表,恰好字段也是laravel auth user里面默认的name email password remember_token等,那么实现起来就方便的多,官方文档和网上的demo示例已经很多了,但是若结合这个laravel/jwt-auth扩展进行多用户认证,其实坑还是蛮多的,由于该扩展0.5.9似乎不支持多用户认证(反正不会帮我们自定义好guard,当然我们可以自己在AuthServiceProvider里用boot方法实现) 我在其github
issue里面看到好多人踩过此坑,结合我遇到的
总结一下,里面一个哥们说,得用^0.1@dev版本
Composer.json文件
内容如下:
{
"name":
"laravel/laravel",
"description":
"The Laravel Framework.",
"keywords":
["framework",
"laravel"],
"license":
"MIT",
"type":
"project",
"require":
{
"php":
">=5.6.4",
"barryvdh/laravel-ide-helper":
"^2.4",
"laravel/framework":
"5.4.*",
"laravel/tinker":
"~1.0",
"predis/predis":
"^1.1"
},
"require-dev":
{
"fzaninotto/faker":
"~1.4",
"mockery/mockery":
"0.9.*",
"phpunit/phpunit":
"~5.7",
"dingo/api":
"1.0.*@dev",
"tymon/jwt-auth":
"^1.0@dev"
},
"autoload":
{
"classmap":
[
"database"
],
"psr-4":
{
"App\\":
"app/"
}
},
"autoload-dev":
{
"psr-4":
{
"Tests\\":
"tests/"
}
},
"scripts":
{
"post-root-package-install":
[
"php -r
\"file_exists('.env') || copy('.env.example', '.env');\""
],
"post-create-project-cmd":
[
"php artisan key:generate"
],
"post-install-cmd":
[
"Illuminate\\Foundation\\ComposerScripts::postInstall",
"php artisan optimize"
],
"post-update-cmd":
[
"Illuminate\\Foundation\\ComposerScripts::postUpdate",
"php artisan optimize"
]
},
"config":
{
"preferred-install":
"dist",
"sort-packages":
true,
"optimize-autoloader":
true
}
}
新增内容如下:
"tymon/jwt-auth":
"^1.0@dev"
App.php配置文件里:
'providers' => [
....
Tymon\JWTAuth\Providers\LaravelServiceProvider::class,
// 上文已经提到过,这里的provider已经不是JWTauthServiceProvider
],
'aliases' => [
....
// 注册JWT门面
'JWTAuth'
=> Tymon\JWTAuth\Facades\JWTAuth::class,
'JWTFactory'
=> Tymon\JWTAuth\Facades\JWTFactory::class,
],
更新包
Composer update -vvv
发布配置文件#(生成文件前先删除jwt.php文件)
php artisan vendor:publish
--provider="Tymon\JWTAuth\Providers\LaravelServiceProvider"
生成密钥#
php artisan jwt:secret
Auth.php文件:
'guards' => [
.....
'admins'
=> [
'driver'
=>
'jwt',
'provider'
=>
'admins',
],
],
'providers' => [
'admins'
=> [
'driver'
=>
'jwt',
'provider'
=>
'admins',
],
],
建立模型admins:
PHP artisan make:mode
Admins
修改内页的内容:
<?php
namespace
App;
use
Illuminate\Database\Eloquent\Model;
use
Illuminate\Auth\Authenticatable;
use
Illuminate\Auth\Passwords\CanResetPassword;
use
Illuminate\Foundation\Auth\Access\Authorizable;
use
Illuminate\Contracts\Auth\Authenticatable
as
AuthenticatableContract;
use
Illuminate\Contracts\Auth\Access\Authorizable
as
AuthorizableContract;
use
Tymon\JWTAuth\Contracts\JWTSubject
as
AuthenticatableUserContract;
class
Admins
extends
Model
implements
AuthenticatableContract,
AuthorizableContract, AuthenticatableUserContract
{
//
use
Authenticatable,
Authorizable,
CanResetPassword;
protected
$table
=
'admins';
//protected $fillable = ['name', 'phone', 'password'];
//protected $hidden = ['password', 'remember_token'];
public function
getJWTIdentifier()
{
return
$this->getKey();
// Eloquent model method
}
/**
*
@return
array
*/
public function
getJWTCustomClaims()
{
return
[];
}
}
在控制器中引用
use Illuminate\Http\Request;
use
Carbon\Carbon;
use
Illuminate\Support\Facades\DB;
use
App\Admins;
use
App\Http\Controllers\Controller;
use
App\Http\Requests;
use
Illuminate\Support\Facades\Validator;
use
Tymon\JWTAuth\Facades\JWTAuth;
use
Illuminate\Support\Facades\Auth;
控制器中加入变量,用于指定生成和解析token
protected
$guard
=
'managers';
生成token
$token = Auth::guard($this->guard)->attempt($input);
解析token
需要传token
$list =
Auth::guard($this->guard)->user();
降地耦合性,取代session,进一步实现前后端分离
减少服务器的压力
可以很简单的实现单点登录
我在实现这个功能的时候查到了这个扩展“tymon/jwt-auth”,最新稳定版是0.5.9。OK照着wiki撸起来,第一步我们先实现API
安装扩展#
composer require tymon/jwt-auth
之后打开config/app.php文件添加service provider 和 aliase
config/app.php#
'providers' => [ .... Tymon\JWTAuth\Providers\JWTAuthServiceProvider::class, // 注意这里的名字,下文会提到 ], 'aliases' => [ .... 'JWTAuth' => Tymon\JWTAuth\Facades\JWTAuth::class ],
OK,现在来发布JWT的配置文件,比如令牌到期时间配置等
php artisan vendor:publish --provider="Tymon\JWTAuth\Providers\JWTAuthServiceProvider"
最后一步需要生成JWT Key
php artisan jwt:generate
创建API路由#
我在创建Api路由的时候会用到一个“cors”中间件,虽然它不是强制性的,但是后面你会发现报类似这样的错
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource athttp://xxx.com/api/register. (Reason: CORS header 'Access-Control-Allow-Origin' missing)
大致翻译下,“跨源请求阻塞:同源策略不允许读取http://kylesean.com/api/register远程资源。(原因:CORS 头“Access-Control-Allow-Origin” 没有)。” 这就是跨域请求导致的错误消息,当然你可以自定义Header,Origin, Method来解决跨域问题,不过我这边推荐一个package:barryvdh/laravel-cors(最新稳定版是0.8.2),这里安装过程省略。
创建中间件#
php artisan make:middleware CORS
进入app/Http/Middleware,编辑CORS.php
app/Http/Middleware/CORS.php#
namespace App\Http\Middleware; use Closure; class CORS { public function handle($request, Closure $next) { header('Access-Control-Allow-Origin: *'); $headers = [ 'Access-Control-Allow-Methods'=> 'POST, GET, OPTIONS, PUT, DELETE', 'Access-Control-Allow-Headers'=> 'Content-Type, X-Auth-Token, Origin' ]; if($request->getMethod() == "OPTIONS") { return Response::make('OK', 200, $headers); } $response = $next($request); foreach($headers as $key => $value) $response->header($key, $value); return $response; } }
Ok,在app/Http/Kernel.php注册中间件
app/Http/Kernel.php#
namespace App\Http; use Illuminate\Foundation\Http\Kernel as HttpKernel; class Kernel extends HttpKernel { ... ... protected $routeMiddleware = [ ... 'cors' => \App\Http\Middleware\CORS::class, ]; }
有了这个中间件我们就解决了跨域问题。接下来回到路由
app/Http/routes.php#
Route::group(['middleware' => ['api','cors'],'prefix' => 'api'], function () { Route::post('register', 'ApiController@register'); // 注册 Route::post('login', 'ApiController@login'); // 登陆 Route::group(['middleware' => 'jwt.auth'], function () { Route::post('get_user_details', 'APIController@get_user_details'); // 获取用户详情 }); });
建议:过滤掉路由api/*下的csrf_token,方便测试开发#
上面的jwt-auth中间件现在还是无效的,接着创建这个middleware
php artisan make:middleware authJWT
同样的我们需要编辑下这个authJWT.php
app/Http/Middleware/authJWT.php#
namespace App\Http\Middleware; use Closure; use Tymon\JWTAuth\Facades\JWTAuth; use Exception; class authJWT { public function handle($request, Closure $next) { try { // 如果用户登陆后的所有请求没有jwt的token抛出异常 $user = JWTAuth::toUser($request->input('token')); } catch (Exception $e) { if ($e instanceof \Tymon\JWTAuth\Exceptions\TokenInvalidException){ return response()->json(['error'=>'Token 无效']); }else if ($e instanceof \Tymon\JWTAuth\Exceptions\TokenExpiredException){ return response()->json(['error'=>'Token 已过期']); }else{ return response()->json(['error'=>'出错了']); } } return $next($request); } }
OK,接着注册该中间件
app/Http/Kernel.php#
namespace App\Http; use Illuminate\Foundation\Http\Kernel as HttpKernel; class Kernel extends HttpKernel { ... ... protected $routeMiddleware = [ ... 'jwt.auth' => \App\Http\Middleware\authJWT::class, ]; }
然后,我们创建控制器管理所有的请求
app/Http/Controllers/ApiController.php#
<?php namespace App\Http\Controllers; use Illuminate\Http\Request; use App\User; use Illuminate\Support\Facades\Hash; use Tymon\JWTAuth\Facades\JWTAuth; class ApiController extends Controller { /*注册*/ public function register(Request $request) { $input = $request->all(); $input['password'] = Hash::make($input['password']); User::create($input); return response()->json(['result'=>true]); } /*登陆*/ public function login(Request $request) { $input = $request->all(); if (!$token = JWTAuth::attempt($input)) { return response()->json(['result' => '邮箱或密码错误.']); } return response()->json(['result' => $token]); } /*获取用户信息*/ public function get_user_details(Request $request) { $input = $request->all(); $user = JWTAuth::toUser($input['token']); return response()->json(['result' => $user]); } }
最后一步我们就来模拟一个请求来测试这个api,为了模拟本地跨域请求,我们简单的新建一个静态页面test.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> <script src="http://apps.bdimg.com/libs/jquery/2.1.1/jquery.min.js"></script> </head> <body> </body> <script> $.ajax({ url: "http://localhost/api/login", dataType: "json", type: "POST", data: {"email":kylesean@qq.com","password":"123456"}, success: function (data) { alert(data.result) } // 这里我们用ajax请求测试,当然你也可以用Angular.js Vue.js }); </script> </html>
这里我们要注意一下,以上测试我们仍是基于User table的,我们来模拟一下login过程,如果账号密码匹配成功,不出意外将会出现类似:
{ "result": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOjEsImlzcyI6Imh0dHA6XC9cL2xvY2FsaG9zdFwvYXBpXC9sb2dpbiIsImlhdCI6MTQ3MzQ1MjUyNSwiZXhwIjoxNDczNDU2MTI1LCJuYmYiOjE0NzM0NTI1MjUsImp0aSI6IjA1M2IzNjliYzYyZjJiZjJmMGMxNjFiNzIxNzY4Y2MzIn0.4WeezpSgEKjNmDFxv1nMU9HxqJgBE7bPyaJDRK4iLeA" }
至此,我们已经实现了jwt的认证功能,那么我们接着完成下一半工作,实现jwt的多用户认证,即Jwt for Multi Auth.
如果你的业务场景是的确需要多用户认证,比如为管理员admin单独生成一张表,恰好字段也是laravel auth user里面默认的name email password remember_token等,那么实现起来就方便的多,官方文档和网上的demo示例已经很多了,但是若结合这个laravel/jwt-auth扩展进行多用户认证,其实坑还是蛮多的,由于该扩展0.5.9似乎不支持多用户认证(反正不会帮我们自定义好guard,当然我们可以自己在AuthServiceProvider里用boot方法实现) 我在其github
issue里面看到好多人踩过此坑,结合我遇到的
总结一下,里面一个哥们说,得用^0.1@dev版本
Composer.json文件
内容如下:
{
"name":
"laravel/laravel",
"description":
"The Laravel Framework.",
"keywords":
["framework",
"laravel"],
"license":
"MIT",
"type":
"project",
"require":
{
"php":
">=5.6.4",
"barryvdh/laravel-ide-helper":
"^2.4",
"laravel/framework":
"5.4.*",
"laravel/tinker":
"~1.0",
"predis/predis":
"^1.1"
},
"require-dev":
{
"fzaninotto/faker":
"~1.4",
"mockery/mockery":
"0.9.*",
"phpunit/phpunit":
"~5.7",
"dingo/api":
"1.0.*@dev",
"tymon/jwt-auth":
"^1.0@dev"
},
"autoload":
{
"classmap":
[
"database"
],
"psr-4":
{
"App\\":
"app/"
}
},
"autoload-dev":
{
"psr-4":
{
"Tests\\":
"tests/"
}
},
"scripts":
{
"post-root-package-install":
[
"php -r
\"file_exists('.env') || copy('.env.example', '.env');\""
],
"post-create-project-cmd":
[
"php artisan key:generate"
],
"post-install-cmd":
[
"Illuminate\\Foundation\\ComposerScripts::postInstall",
"php artisan optimize"
],
"post-update-cmd":
[
"Illuminate\\Foundation\\ComposerScripts::postUpdate",
"php artisan optimize"
]
},
"config":
{
"preferred-install":
"dist",
"sort-packages":
true,
"optimize-autoloader":
true
}
}
新增内容如下:
"tymon/jwt-auth":
"^1.0@dev"
App.php配置文件里:
'providers' => [
....
Tymon\JWTAuth\Providers\LaravelServiceProvider::class,
// 上文已经提到过,这里的provider已经不是JWTauthServiceProvider
],
'aliases' => [
....
// 注册JWT门面
'JWTAuth'
=> Tymon\JWTAuth\Facades\JWTAuth::class,
'JWTFactory'
=> Tymon\JWTAuth\Facades\JWTFactory::class,
],
更新包
Composer update -vvv
发布配置文件#(生成文件前先删除jwt.php文件)
php artisan vendor:publish
--provider="Tymon\JWTAuth\Providers\LaravelServiceProvider"
生成密钥#
php artisan jwt:secret
Auth.php文件:
'guards' => [
.....
'admins'
=> [
'driver'
=>
'jwt',
'provider'
=>
'admins',
],
],
'providers' => [
'admins'
=> [
'driver'
=>
'jwt',
'provider'
=>
'admins',
],
],
建立模型admins:
PHP artisan make:mode
Admins
修改内页的内容:
<?php
namespace
App;
use
Illuminate\Database\Eloquent\Model;
use
Illuminate\Auth\Authenticatable;
use
Illuminate\Auth\Passwords\CanResetPassword;
use
Illuminate\Foundation\Auth\Access\Authorizable;
use
Illuminate\Contracts\Auth\Authenticatable
as
AuthenticatableContract;
use
Illuminate\Contracts\Auth\Access\Authorizable
as
AuthorizableContract;
use
Tymon\JWTAuth\Contracts\JWTSubject
as
AuthenticatableUserContract;
class
Admins
extends
Model
implements
AuthenticatableContract,
AuthorizableContract, AuthenticatableUserContract
{
//
use
Authenticatable,
Authorizable,
CanResetPassword;
protected
$table
=
'admins';
//protected $fillable = ['name', 'phone', 'password'];
//protected $hidden = ['password', 'remember_token'];
public function
getJWTIdentifier()
{
return
$this->getKey();
// Eloquent model method
}
/**
*
@return
array
*/
public function
getJWTCustomClaims()
{
return
[];
}
}
在控制器中引用
use Illuminate\Http\Request;
use
Carbon\Carbon;
use
Illuminate\Support\Facades\DB;
use
App\Admins;
use
App\Http\Controllers\Controller;
use
App\Http\Requests;
use
Illuminate\Support\Facades\Validator;
use
Tymon\JWTAuth\Facades\JWTAuth;
use
Illuminate\Support\Facades\Auth;
控制器中加入变量,用于指定生成和解析token
protected
$guard
=
'managers';
生成token
$token = Auth::guard($this->guard)->attempt($input);
解析token
需要传token
$list =
Auth::guard($this->guard)->user();
相关文章推荐
- Laravel 5.2 使用 JWT 完成多用户认证
- laravel 使用JWT实现用户认证
- Laravel 5 中使用 JWT(Json Web Token) 实现基于API的用户认证
- [Laravel 5.2]二、注册、登陆及用户认证
- Laravel 5.2 中多用户认证实现(前台和后台登录)
- Laravel 5.3 使用内置的 Auth 组件实现多用户认证功能以及登陆才能访问后台的功能的一种实现方法
- Laravel 5.2 中多用户认证实现(前台和后台登录)
- Laravel使用policy完成用户授权
- laravel-jwt用户认证
- Spring Boot实战之Filter实现使用JWT进行接口认证 jwt(json web token) 用户发送按照约定,向服务端发送 Header、Payload 和 Signature,
- 使用SpringBoot + Ignite + JWT实现用户认证
- Laravel-使用中间件做用户认证和权限管理
- FTP使用MariaDB完成虚拟用户认证
- 使用DFS和组策略完成各部门文件夹的认证及限额操作
- Spring Security 使用数据库用户进行认证
- 使用css完成引导用户按照流程完成任务的进度导航条
- 使用RADIUS来认证***用户
- Laravel 5.2使用phpunit提示command not found
- Lumen上使用Dingo/Api做API开发时用JWT-Auth做认证的实现
- laravel5.2总结--redis使用