程序猿的进阶屋

php 实现 jwt

2019-08-29  本文已影响0人  零一间

介绍

JWT提供了一种创建和验证访问令牌的方法,而无需中央存储(如数据库)。

JWT使用JSON Web签名 和 公钥加密 来确定其有效性。

JWT 的数据结构

HEADER.PAYLOAD.SIGNATURE

中间用点(.)分隔成三个部分。注意,JWT 内部是没有换行的。

HEADER

{"typ": "JWT", "alg":"RS256"}

Header 部分是一个 JSON 对象,描述 JWT 的元数据。

Payload

{
  "id": "394a71988caa6cc30601e43f5b6569d52cd7f6df",
  "jti": "394a71988caa6cc30601e43f5b6569d52cd7f6df",
  "iss": "issuer_id",
  "aud": "client_id",
  "sub": "user_id",
  "exp": 1483711650,
  "iat": 1483708050,
  "token_type": "bearer",
  "scope": "onescope twoscope"
}

Payload 部分也是一个 JSON 对象,用来存放实际需要传递的数据。JWT 规定了7个官方字段,供选用。除了官方字段,还可以在这个部分定义私有字段.

Signature

是对前两部分的签名,防止数据篡改。

需要指定一个密钥(secret)。使用 Header 里面指定的签名算法(默认是 HMAC SHA256),按照下面的公式产生签名。

HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
secret)

算出签名以后,把 Header、Payload、Signature 三个部分拼成一个字符串,每个部分之间用"点"(.)分隔,就可以返回给用户。

Base64URL

Header 和 Payload 串型化的算法是 Base64URL。这个算法跟 Base64 算法基本类似,但有一些小的不同。

JWT 作为一个令牌(token),有些场合可能会放到 URL(比如 api.example.com/?token=xxx)。Base64 有三个字符+、/和=,在 URL 里面有特殊含义,所以要被替换掉:=被省略、+替换成-,/替换成_ 。这就是 Base64URL 算法。

JWT 的使用方式

客户端收到服务器返回的 JWT,可以储存在 Cookie 里面,也可以储存在 localStorage。

此后,客户端每次与服务器通信,都要带上这个 JWT。你可以把它放在 Cookie 里面自动发送,但是这样不能跨域,所以更好的做法是放在 HTTP 请求的头信息Authorization字段里面。

获取jwt,携带jwt获取资源,服务端进行鉴权。

JWT 的几个特点

创建公钥和私钥对

mkdir keys
cd keys
openssl genrsa -out privkey.pem 2048
openssl rsa -in privkey.pem -pubout -out pubkey.pem

认证token服务


<?php
/**
 * Created by PhpStorm.
 * User: jinchunguang
 * Date: 19-8-23
 * Time: 下午1:21
 */

// token.php

// error reporting (this is a demo, after all!)
ini_set('display_errors',1);
error_reporting(E_ALL);

// Autoloading (composer is preferred, but for this example let's just do this)
require_once('oauth2-server-php/src/OAuth2/Autoloader.php');
OAuth2\Autoloader::register();

// your public key strings can be passed in however you like
// (there is a public/private key pair for testing already in the oauth library)
$publicKey  = file_get_contents('./keys/pubkey.pem');
$privateKey = file_get_contents('./keys/privkey.pem');

// create storage
$storage = new OAuth2\Storage\Memory(array(
    'keys' => array(
        'public_key'  => $publicKey,
        'private_key' => $privateKey,
    ),
    // add a Client ID for testing
    'client_credentials' => array(
        'CLIENT_ID' => array('client_secret' => 'CLIENT_SECRET')
    ),
));

$server = new OAuth2\Server($storage, array(
    'use_jwt_access_tokens' => true,
));
$server->addGrantType(new OAuth2\GrantType\ClientCredentials($storage)); // minimum config

// send the response
$server->handleTokenRequest(OAuth2\Request::createFromGlobals())->send();


启动服务

php -S localhost:3000 &

获取access_token

curl http://localhost:3000/token.php -u 'CLIENT_ID:CLIENT_SECRET' -d "grant_type=client_credentials" |jq
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   755    0   726  100    29  27923   1115 --:--:-- --:--:-- --:--:-- 30200
{
  "access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJpZCI6ImZiNzhiMmJjMmYyOGQwYzZlYTVhN2Y5YTZhN2Y0NjhhZmQxZWY0ZGIiLCJqdGkiOiJmYjc4YjJiYzJmMjhkMGM2ZWE1YTdmOWE2YTdmNDY4YWZkMWVmNGRiIiwiaXNzIjoiIiwiYXVkIjoiQ0xJRU5UX0lEIiwic3ViIjpudWxsLCJleHAiOjE1NjY1NDIzNjEsImlhdCI6MTU2NjUzODc2MSwidG9rZW5fdHlwZSI6ImJlYXJlciIsInNjb3BlIjpudWxsfQ.mSaXWNRQzFgPW1BJtxb8zM1Ktu0LkNru5Wzi1m6PTEy59yVZ3T6MbwlQzp3WmP0H-6eZhcQHPw1G-AHSNoR3Di_4umyvmcjCiHCixBWlcHy2ELZkeXOTrjjaoEJ-vpH33qfV7hh47QUHyJPEKHi-WMMoFfjCyhWxdRY-slV7oiWu69IaWLT8KmEY2FspjcUlWnd0jy4FWwA5jmyEY4qdke0ux2YHAwtKxT-y_i_2qQTK6T5AHe2GMyCy3Vk2dp2voX3igxpNmQ9zTCHI66Brz5OWWbG9SQVPB8udxLh_hLsLLrhuh1Q3DoaAjGho7Z8nZ0DV4vx2FPQDmnYbm5m4YA",
  "expires_in": 3600,
  "token_type": "bearer",
  "scope": null
}

资源服务器认证


<?php
/**
 * Created by PhpStorm.
 * User: jinchunguang
 * Date: 19-8-23
 * Time: 下午1:25
 */

require_once('oauth2-server-php/src/OAuth2/Autoloader.php');
OAuth2\Autoloader::register();
/* for a Resource Server (minimum config) */
$publicKey = file_get_contents('./keys/pubkey.pem');

// no private key necessary
$keyStorage = new OAuth2\Storage\Memory(array('keys' => array(
    'public_key'  => $publicKey,
)));

$server = new OAuth2\Server($keyStorage, array(
    'use_jwt_access_tokens' => true,
));

// verify the JWT Access Token in the request
if (!$server->verifyResourceRequest(OAuth2\Request::createFromGlobals())) {
    exit("Failed");
}

// 正常业务逻辑
echo "Success!";


cli访问:

curl -i  http://localhost:3000/resource.php\?access_token\=eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJpZCI6ImZiNzhiMmJjMmYyOGQwYzZlYTVhN2Y5YTZhN2Y0NjhhZmQxZWY0ZGIiLCJqdGkiOiJmYjc4YjJiYzJmMjhkMGM2ZWE1YTdmOWE2YTdmNDY4YWZkMWVmNGRiIiwiaXNzIjoiIiwiYXVkIjoiQ0xJRU5UX0lEIiwic3ViIjpudWxsLCJleHAiOjE1NjY1NDIzNjEsImlhdCI6MTU2NjUzODc2MSwidG9rZW5fdHlwZSI6ImJlYXJlciIsInNjb3BlIjpudWxsfQ.mSaXWNRQzFgPW1BJtxb8zM1Ktu0LkNru5Wzi1m6PTEy59yVZ3T6MbwlQzp3WmP0H-6eZhcQHPw1G-AHSNoR3Di_4umyvmcjCiHCixBWlcHy2ELZkeXOTrjjaoEJ-vpH33qfV7hh47QUHyJPEKHi-WMMoFfjCyhWxdRY-slV7oiWu69IaWLT8KmEY2FspjcUlWnd0jy4FWwA5jmyEY4qdke0ux2YHAwtKxT-y_i_2qQTK6T5AHe2GMyCy3Vk2dp2voX3igxpNmQ9zTCHI66Brz5OWWbG9SQVPB8udxLh_hLsLLrhuh1Q3DoaAjGho7Z8nZ0DV4vx2FPQDmnYbm5m4YA    
HTTP/1.1 200 OK
Host: localhost:3000
Date: Fri, 23 Aug 2019 05:41:36 GMT
Connection: close
X-Powered-By: PHP/7.2.19-0ubuntu0.18.04.2
Content-type: text/html; charset=UTF-8

Success!% 

参考:http://www.ruanyifeng.com/blog/2018/07/json_web_token-tutorial.html

上一篇 下一篇

猜你喜欢

热点阅读