您好,欢迎访问一九零五行业门户网

Laravel 5 中使用 JWT(Json Web Token) 实现基于API的用户认证

在javascript前端技术大行其道的今天,我们通常只需在后台构建api提供给前端调用,并且后端仅仅设计为给前端移动app调用。用户认证是web应用的重要组成部分,基于api的用户认证有两个最佳解决方案 —— oauth 2.0 和jwt(json web token)。
1、jwt定义及其组成 jwt(json web token)是一个非常轻巧的规范。这个规范允许我们使用jwt在用户和服务器之间传递安全可靠的信息。
一个jwt实际上就是一个字符串,它由三部分组成,头部、载荷与签名。
载荷(payload) 我们先将用户认证的操作描述成一个json对象。其中添加了一些其他的信息,帮助今后收到这个jwt的服务器理解这个jwt。
{ sub: 1, iss: http://localhost:8000/auth/login, iat: 1451888119, exp: 1454516119, nbf: 1451888119, jti: 37c107e4609ddbcc9c096ea5ee76c667}
这里面的前6个字段都是由jwt的标准所定义的。
sub: 该jwt所面向的用户 iss: 该jwt的签发者 iat(issued at): 在什么时候签发的token exp(expires): token什么时候过期 nbf(not before):token在此时间之前不能被接收处理 jti:jwt id为web token提供唯一标识 这些定义都可以在 标准 中找到。
将上面的json对象进行base64编码可以得到下面的字符串:
eyjzdwiioiixiiwiaxnzijoiahr0cdpcl1wvbg9jywxob3n0ojgwmdfcl2f1dghcl2xvz2luiiwiawf0ijoxnduxodg4mte5lcjlehaioje0ntq1mtyxmtksim5izii6mtq1mtg4odexoswianrpijoimzdjmta3ztq2mdlkzgjjyzljmdk2zwe1zwu3nmm2njcifq
这个字符串我们将它称作jwt的payload(载荷)。
如果你使用node.js,可以用node.js的包base64url来得到这个字符串:
var base64url = require('base64url')var header = { from_user: b, target_user: a}console.log(base64url(json.stringify(header)))
注:base64是一种编码,也就是说,它是可以被翻译回原来的样子来的。它并不是一种加密过程。
头部(header) jwt还需要一个头部,头部用于描述关于该jwt的最基本的信息,例如其类型以及签名所用的算法等。这也可以被表示成一个json对象:
{ typ: jwt, alg: hs256}
在这里,我们说明了这是一个jwt,并且我们所用的签名算法(后面会提到)是hs256算法。
对它也要进行base64编码,之后的字符串就成了jwt的header(头部):
eyj0exaioijkv1qilcjhbgcioijiuzi1nij9
签名(签名) 将上面的两个编码后的字符串都用句号.连接在一起(头部在前),就形成了:
eyj0exaioijkv1qilcjhbgcioijiuzi1nij9.eyjzdwiioiixiiwiaxnzijoiahr0cdpcl1wvbg9jywxob3n0ojgwmdfcl2f1dghcl2xvz2luiiwiawf0ijoxnduxodg4mte5lcjlehaioje0ntq1mtyxmtksim5izii6mtq1mtg4odexoswianrpijoimzdjmta3ztq2mdlkzgjjyzljmdk2zwe1zwu3nmm2njcifq
最后,我们将上面拼接完的字符串用hs256算法进行加密。在加密的时候,我们还需要提供一个密钥(secret):
hmacsha256( base64urlencode(header) + . + base64urlencode(payload), secret)
这样就可以得到我们加密后的内容:
wyoq95rjayq2ff3aj8evcsaumep0kuqccjdennfnat4
这一部分又叫做签名。
最后将这一部分签名也拼接在被签名的字符串后面,我们就得到了完整的jwt:
eyj0exaioijkv1qilcjhbgcioijiuzi1nij9.eyjzdwiioiixiiwiaxnzijoiahr0cdpcl1wvbg9jywxob3n0ojgwmdfcl2f1dghcl2xvz2luiiwiawf0ijoxnduxodg4mte5lcjlehaioje0ntq1mtyxmtksim5izii6mtq1mtg4odexoswianrpijoimzdjmta3ztq2mdlkzgjjyzljmdk2zwe1zwu3nmm2njcifq.wyoq95rjayq2ff3aj8evcsaumep0kuqccjdennfnat4
2、集成jwt到laravel 5 安装 我们使用composer安装jwt扩展包:
composer require tymon/jwt-auth 0.5.*
配置 安装完成后,需要在 config/app.php 中注册相应的服务提供者:
tymon\jwtauth\providers\jwtauthserviceprovider::class
然后注册需要用到的对应门面:
'jwtauth' => tymon\jwtauth\facades\jwtauth::class'jwtfactory' => tymon\jwtauth\facades\jwtfactory::class
然后发布相应配置文件:
php artisan vendor:publish --provider=tymon\jwtauth\providers\jwtauthserviceprovider
最后生成密钥:
php artisan jwt:generate
如果你想要将其添加到 .env 文件中,在 .env 中创建 jwt_secret 字段并再次执行生成密钥的命令。
在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直到它们失效 创建token 创建用户token最常用的方式就是通过登录实现用户认证,如果成功则返回相应用户的token。这里假设我们有一个 authenticatecontroller :
use jwtauth;use tymon\jwtauth\exceptions\jwtexception;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);
此外,还可以使用 tymon\jwtauth\payloadfactory 实例(或者 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 onrewritecond %{http:authorization} ^(.*)rewriterule .* - [e=http_authorization:%1]
或者将token信息包含到url中:
http://api.mysite.com/me?token={yourtokenhere}
要从请求中获取token,你可以这么做:
// this will set the token on the objectjwtauth::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 controllerpublic function getauthenticateduser(){ try { if (! $user = jwtauth::parsetoken()->authenticate()) { return response()->json(['user_not_found'], 404); } } catch (tymon\jwtauth\exceptions\tokenexpiredexception $e) { return response()->json(['token_expired'], $e->getstatuscode()); } catch (tymon\jwtauth\exceptions\tokeninvalidexception $e) { return response()->json(['token_invalid'], $e->getstatuscode()); } catch (tymon\jwtauth\exceptions\jwtexception $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扩展还提供了两个中间件 getuserfromtoken 和 refreshtoken ,前者用于在请求头和参数中检查是否包含token,并尝试对其解码,后者会再次从请求中解析token,并顺序刷新token(同时废弃老的token)并将其作为下一个响应的一部分。要使用这两个中间件,需要到 app/http/kernel.php 下的 $routemiddleware 属性中注册它们:
protected $routemiddleware = [ ... 'jwt.auth' => 'tymon\jwtauth\middleware\getuserfromtoken', 'jwt.refresh' => 'tymon\jwtauth\middleware\refreshtoken',];
jwt让用户认证变得简单和安全,token会被保存到本地的 storage/web 或cookie中,使用jwt,基于api的用户认证将不再困难。
其它类似信息

推荐信息