jwt笔记
大约 4 分钟
jwt笔记
相关链接
https://github.com/tymondesigns/jwt-auth/wiki
基于JWT(Json Web Token)的授权方式
JWT 是JSON风格轻量级的授权和身份认证规范,可实现无状态、分布式的Web应用授权;
从客户端请求服务器获取token, 用该token 去访问实现了jwt认证的web服务器。
token 可保存自定义信息,如用户基本信息, web服务器用key去解析token,就获取到请求用户的信息了;
很方便解决跨域授权的问题,因为跨域无法共享cookie,用jwt完美解决了。
JWT缺点
- 一旦拿到token, 可用它访问服务器,直到过期,中间服务器无法控制它, 如是它失效(有解决方案: 在 token 中保存信息,可添加额外的验证,如加一个 flag, 把数据库对应的flag失效,来控制token有效性)。
- token 的过期时间设置很关键,一般把它设到凌晨少人访问时失效,以免用户使用过程中失效而丢失数据。
- token保存的信息有限,且都是字符串。
JWT字符串解析
JWT是Auth0提出的通过对JSON进行加密签名来实现授权验证的方案,编码之后的JWT看起来是这样的一串字符:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.
eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.
TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ
由.分为三段,通过解码可以得到:
// 1. Headers
// 包括类别(typ)、加密算法(alg);
{
"alg": "HS256",
"typ": "JWT"
}
// 2. Claims
// 包括需要传递的用户信息;
{
"sub": "1234567890",
"name": "John Doe",
"admin": true
}
// 3. Signature
// 根据alg算法与私有秘钥进行加密得到的签名字串;
// 这一段是最重要的敏感信息,只能在服务端解密;
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
SECREATE_KEY
)
JWT安装
- 安装JWT
composer require tymon/jwt-auth
- 注册服务提供者 config/app.php
'providers' => [
Tymon\JWTAuth\Providers\JWTAuthServiceProvider::class
]
- 注册门面 config/app.php
'aliases' => [
'JWTAuth' => Tymon\JWTAuth\Facades\JWTAuth::class,
'JWTFactory' => Tymon\JWTAuth\Facades\JWTFactory::class,
]
- 写入配置文件 config/jwt.php
php artisan vendor:publish --provider="Tymon\JWTAuth\Providers\JWTAuthServiceProvider"
在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:generate
jwt测试用例
-- 生成控制器
php artisan make:controller JWTController
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use JWTAuth; // use Facade
use Tymon\JWTAuth\Exceptions\JWTException;
use App\User;
class JWTController extends Controller
{
public function index(Request $request)
{
// 根据用户信息生成一个token
$token = JWTAuth::attempt(['email' => 'test@qq.com', 'password' => '123456']);
var_dump($token);
return 'JWTController';
}
/**
* 获取用户相关信息
* @param Request $request
* @return \Illuminate\Http\JsonResponse
*/
public function getUserToken(Request $request)
{
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());
}
// 如果token验证通过,则返回用户相关信息
return response()->json(compact('user'));
}
/**
* 用户验证
* @param Request $request
* @return \Illuminate\Http\JsonResponse
*/
public function authenticate(Request $request)
{
// 获取表单信息
$email = $request->get('email');
$password = $request->get('password');
// 生成表单信息
$userInfo = [
'email' => $email,
'password' => $password,
];
try {
// 根据用户信息试着生成一个token
if (!$token = JWTAuth::attempt($userInfo)) {
return response()->json(['error' => 'invalid_credentials'], 401);
}
} catch (JWTException $e) {
// 无法生成token
return response()->json(['error' => 'could_not_create_token'], 500);
}
// 验证成功后返回token
return response()->json(compact('token'));
}
/**
* 用户注册
* @param Request $request
* @return string 成功后返回token
*/
public function register(Request $request)
{
// 获取表单信息
$name = $request->get('name');
$email = $request->get('email');
$password = bcrypt($request->get('password'));
// 生成表单信息
$userInfo = [
'name' => $name,
'email' => $email,
'password' => $password,
];
$result = User::where('email', '=', $email)->first();
if ($result) {
return ['此用户已经注册过'];
}
// 根据用户生成token
$user = User::create($userInfo);
$token = JWTAuth::fromUser($user);
// 将token存储在数据库中
if ($token) {
User::where('email', '=', $request->get('email'))->update(['remember_token' => $token]);
}
// 返回token
return response()->json(compact('token'));
}
}
-- 添加路由 routes/api.php
// JWT路由
$api->version(['v1', 'v2'], function($api){
$api->get('jwt', 'App\Http\Controllers\JWTController@index');
$api->get('jwt/register', 'App\Http\Controllers\JWTController@register'); // 注册
$api->get('jwt/authenticate', 'App\Http\Controllers\JWTController@authenticate'); // 登录
$api->get('jwt/getusertoken', 'App\Http\Controllers\JWTController@getusertoken'); // 登录
});
使用http://html.dev/api/jwt
进行访问
-- 配置数据库
首先要配置.env
里数据库的连接信息
// 修改文件
`database/migrations/2014_10_12_000000_create_users_table.php`
$table->string('email', 500)->unique();
`database/migrations/2014_10_12_100000_create_password_resets_table.php`
$table->string('email', 500)->index();
php artisan migrate
-- 测试链接
http://html.dev/api/jwt/getusertoken
?name=test
&email=test@qq.com
&password=123456
&token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9
.eyJzdWIiOjcsImlzcyI6Imh0dHA6Ly9odG1sLmRldi9hcGkvand0L3JlZ2lzdGVyIiwiaWF0IjoxNDk5NTk0MDQwLCJleHAiOjE0OTk1OTc2NDAsIm5iZiI6MTQ5OTU5NDA0MCwianRpIjoibUlVRHg5b3NxTmJLZVlLNyJ9
.eij1EPrV2wmOA83aAal2qQiDGdKEJ5qbUAR0g_StO8M