ThinkPHP 5 Easyui 实现 JWT 验证

直接上代码  先引入JWT核心文件

   /**
    * Created by PhpStorm.
    * User: mybook-lhp
    * Date: 18/1/29
    * Time: 下午2:10
    */

   namespace app\common\Service;


   use think\Exception;

    class JwtService
   {
      /**
       * 编码
       * @param $payload
       * @param $key
       * @param string $algo
       * @return string
       * @throws Exception
       */
      static public function encode($payload, $key, $algo = 'HS256')
      {
         $header = static::generateJwtHeader($payload, $algo);

         $segments = array(
            static::urlSafeB64Encode(json_encode($header)),
            static::urlSafeB64Encode(json_encode($payload))
         );

         $signing_input = implode('.', $segments);

         $signature = static::sign($signing_input, $key, $algo);
         $segments[] = static::urlsafeB64Encode($signature);

         return implode('.', $segments);
      }

      /**
       * 解码
       * @param $jwt
       * @param null $key
       * @param bool $allowedAlgorithms
       * @return bool|mixed
       * @throws Exception
       */
      static public function decode($jwt, $key = null, $allowedAlgorithms = true)
      {
         if (!strpos($jwt, '.')) {
            return false;
         }

         $tks = explode('.', $jwt);

         if (count($tks) != 3) {
            return false;
         }

         list($headb64, $payloadb64, $cryptob64) = $tks;

         if (null === ($header = json_decode(static::urlSafeB64Decode($headb64), true))) {
            return false;
         }

         if (null === $payload = json_decode(static::urlSafeB64Decode($payloadb64), true)) {
            return false;
         }

         $sig = static::urlSafeB64Decode($cryptob64);

         if ((bool)$allowedAlgorithms) {
            if (!isset($header['alg'])) {
               return false;
            }

            // check if bool arg supplied here to maintain BC
            if (is_array($allowedAlgorithms) && !in_array($header['alg'], $allowedAlgorithms)) {
               return false;
            }

            if (!static::verifySignature($sig, "$headb64.$payloadb64", $key, $header['alg'])) {
               return false;
            }
         }

         return $payload;
      }

      /**
       * @param $signature
       * @param $input
       * @param $key
       * @param string $algo
       * @return bool
       * @throws Exception
       */
      static private function verifySignature($signature, $input, $key, $algo = 'HS256')
      {
         // use constants when possible, for HipHop support
         switch ($algo) {
            case'HS256':
            case'HS384':
            case'HS512':
               return static::hash_equals(
                  static::sign($input, $key, $algo),
                  $signature
               );

            case 'RS256':
               return openssl_verify($input, $signature, $key, defined('OPENSSL_ALGO_SHA256') ? OPENSSL_ALGO_SHA256 : 'sha256') === 1;

            case 'RS384':
               return @openssl_verify($input, $signature, $key, defined('OPENSSL_ALGO_SHA384') ? OPENSSL_ALGO_SHA384 : 'sha384') === 1;

            case 'RS512':
               return @openssl_verify($input, $signature, $key, defined('OPENSSL_ALGO_SHA512') ? OPENSSL_ALGO_SHA512 : 'sha512') === 1;

            default:
               throw new Exception("Unsupported or invalid signing algorithm.");
         }
      }

      /**
       * @param $input
       * @param $key
       * @param string $algo
       * @return string
       * @throws Exception
       */
      static private function sign($input, $key, $algo = 'HS256')
      {
         switch ($algo) {
            case 'HS256':
               return hash_hmac('sha256', $input, $key, true);

            case 'HS384':
               return hash_hmac('sha384', $input, $key, true);

            case 'HS512':
               return hash_hmac('sha512', $input, $key, true);

            case 'RS256':
               return static::generateRSASignature($input, $key, defined('OPENSSL_ALGO_SHA256') ? OPENSSL_ALGO_SHA256 : 'sha256');

            case 'RS384':
               return static::generateRSASignature($input, $key, defined('OPENSSL_ALGO_SHA384') ? OPENSSL_ALGO_SHA384 : 'sha384');

            case 'RS512':
               return static::generateRSASignature($input, $key, defined('OPENSSL_ALGO_SHA512') ? OPENSSL_ALGO_SHA512 : 'sha512');

            default:
               throw new Exception("Unsupported or invalid signing algorithm.");
         }
      }

      /**
       * @param $input
       * @param $key
       * @param string $algo
       * @return mixed
       * @throws Exception
       */
      static private function generateRSASignature($input, $key, $algo)
      {
         if (!openssl_sign($input, $signature, $key, $algo)) {
            throw new Exception("Unable to sign data.");
         }

         return $signature;
      }

      /**
       * @param string $data
       * @return string
       */
      static public function urlSafeB64Encode($data)
      {
         $b64 = base64_encode($data);
         $b64 = str_replace(array('+', '/', "\r", "\n", '='),
            array('-', '_'),
            $b64);

         return $b64;
      }

      /**
       * @param string $b64
       * @return mixed|string
       */
      static public function urlSafeB64Decode($b64)
      {
         $b64 = str_replace(array('-', '_'),
            array('+', '/'),
            $b64);

         return base64_decode($b64);
      }

      /**
       * Override to create a custom header
       */
      static protected function generateJwtHeader($payload, $algorithm)
      {
         return [
            'typ' => 'JWT',
            'alg' => $algorithm,
         ];
      }

      /**
       * @param string $a
       * @param string $b
       * @return bool
       */
      static protected function hash_equals($a, $b)
      {
         if (function_exists('hash_equals')) {
            return hash_equals($a, $b);
         }
         $diff = strlen($a) ^ strlen($b);
         for ($i = 0; $i < strlen($a) && $i < strlen($b); $i ++) {
            $diff |= ord($a[$i]) ^ ord($b[$i]);
         }

         return $diff === 0;
      }
   }
第二步 登陆控制器

这里主要是获取登陆用户名和密码 然后账号密码验证通过后生成用户唯一标示 (姑且ji OpenID ),其中$model中放置一些非敏感信息。


   namespace app\admin\controller;

   use app\common\model\UserModel;
   use app\common\Service\JwtService;
   use app\common\utils\UtilEncryption;
   use app\common\utils\UtilFilter;
   use app\common\utils\UtilStateCode;
   use think\Controller;


   class Login extends Controller
   {

      public function token()
      {

         $parm = $this->request->param();

         $lname = isset($parm['login_name']) ? trim($parm['login_name']) : "";
  
         $lname = UtilFilter::addslashesStr($lname);

         $enter_pwd = isset($parm['pwd']) ? trim($parm['pwd']) : "";
         $pwd = UtilEncryption::encryptMD5($enter_pwd, config('auth.auto_key'));
         $model = UserModel::getUser(['username' => $lname, 'password' => $pwd]);

         if ($model) {
            unset($model['password']);
            $token = JwtService::encode($model, config('auth.auto_key'));

            return json(['token' => $token]);
         } else {
            $this->error('请求数据错误', UtilStateCode::ALL_ERROR);
         }
      }



   }
第三步 请求访问验证 

其中为http请求头里面回传回来的OpenID

HTTP_X_AUTH_TOKEN
$token = $_SERVER['HTTP_X_AUTH_TOKEN'];
         if (!empty($token)) {
            $users = JwtService::decode($token, config('auth.auto_key'));
            if ($users) {
               $loginflag = true;
               $this->user = $users;
            }
         }


   namespace app\common\controller;


   use app\common\Service\AuthServer;
   use app\common\Service\JwtService;
   use app\common\utils\UtilStateCode;
   use think\Controller;


   class BaseController extends Controller
   {
      protected $user   = null;
      public    $map    = null;
      public    $put    = null;
      public    $put_id = null;

      public function __construct()
      {
         parent::__construct();
         $this->map();
         $this->put();
         config('app.default_return_type', 'json');
      }

      public function initialize()
      {
         parent::initialize(); // TODO: Change the autogenerated stub

         $loginflag = false;
         $accessflag = true;

         $token = $this->request->header('X-Auth-Token', null);

         if ($token === null) {
            $this->error('Token不存在,你没有权限访问!');
         }
         $token = $_SERVER['HTTP_X_AUTH_TOKEN'];
         if (!empty($token)) {
            $users = JwtService::decode($token, config('auth.auto_key'));
            if ($users) {
               $loginflag = true;
               $this->user = $users;
            }
         }
         $action = $this->request->action();
         $controller = $this->request->controller();
         $module = $this->request->module();

         $URL = $module . '/' . $controller . '/' . $action;
         if (!static::authcheck($URL, $users['id'])) {

            return json($users['username'] . '很抱歉,此项操作您没有权限!');

         }

         if ($loginflag && $accessflag) {
            return true;
         } else {
            if (!$loginflag) {
               $this->error("未登录", UtilStateCode::LOGIN_REQUIRE);

            } else {
               $this->error("没有权限", UtilStateCode::ACCESS_ERROR);
            }
         }
      }

      protected function map()
      {
         $this->map['id'] = $this->request->param('id', false);
         $this->map['page'] = $this->request->param('page', '1');
         $this->map['rows'] = $this->request->param('rows', '20');

         $this->map['order'] = [$this->request->param('sort', 'id') => $this->request->param('order', 'desc')];

         return $this;
      }

      protected function put()
      {
         $this->put_id = $this->request->get('id');
         $this->put = $this->request->put();
         return $this;

      }

      /**
       * 检查权限
       * @param name string|array  需要验证的规则列表,支持逗号分隔的权限规则或索引数组
       * @param uid  int           认证用户的id
       * @param string mode        执行check的模式
       * @param relation string    如果为 'or' 表示满足任一条规则即通过验证;如果为 'and'则表示需满足所有规则才能通过验证
       * @return boolean           通过验证返回true;失败返回false
       */
      static protected function authcheck($name, $uid, $type = 1, $mode = 'url', $relation = 'or')
      {
         if (!in_array($uid, config('auth.ADMINISTRATOR'))) {
            $auth = new AuthServer();
            return $auth->check($name, $uid, $type, $mode, $relation) ? true : false;
         } else {
            return true;
         }
      }

   }
以上是PHP的实现

下面是Easyui的实现

js登陆代码

var loginFun = function () {
    if ($('#loginform').form('validate')) {

        Qrck.post(Qrck.baseApiLoginUrl, $('#loginform').serialize(), function () {
            $.messager.progress({
                text: '登录验证中请稍后……',

            });
        }, function (data) {
            var login_name = $('#username').val();

            $.cookie('login_name', login_name, {path: Qrck.cookiePath});
            $.cookie('token', data.token, {path: Qrck.cookiePath});

            window.location.href = Qrck.baseHtmlUrl + Qrck.baseHtmlMain;
        }, function (data) {
            $.messager.progress('close');
            $.messager.show({
                title: '提示',
                msg: '用户不存在或密码错误,请重新登录',
                showType: 'slide',
            });
        });
    }
};
用户登录后会得到OpenID 也就是上面的token  ,然后将Token存入cookie中

GetAjaxData: function (url, method, parm, beforeSend, success, error) {

    var dataurl = this.baseApiUrl + url;
    $.ajax({
        headers: {
            "X-Auth-Token": $.cookie('token')
        },
        type: method,
        url: dataurl,
        cache: false,
        async: this.asyncFlag,
        dataType: this.dataType,
        data: parm,
        beforeSend: function () {
            if (typeof beforeSend === "function") {
                beforeSend();
            }
        },
        success: function (result) {
            if (typeof success === "function") {
                success(result);
            }
        },
        error: function (result) {
            if (typeof error === "function") {
                error(result);
            }
        },
    });
},
在每一次请求的ajax请求时,都将OpenID放入http请求头里面,这样就不用单独传参。

JWT 类可以支持OpenSSL证书的加密更安全




你可能感兴趣的:(分享,原创)