基于 CodeIgniter 构建 JWT RESTfull API Server

    |     2019年6月18日   |   学习偶记   |     评论已关闭   |    4497

本文转自:https://www.lovchun.com/posts/build-jwt-restfull-api-server-in-codeigniter-1.html 【文中图片请点击看大图。】

CodeIgniter

以 3.1.7 版本为例,下载地址:http://codeigniter.org.cn/ 。

下载后,解压至当前文件夹,你会得到一个 CodeIgniter-3.1.7 的文件夹,将它重命名为你喜欢的项目名,我的是 JWT-RESTfull-IN-CI-Tutorial ,如图所示:

启动项目

接下来,用 IDE 或者其他什么,例如 PhpStorm、NetBeans、Sublime 等打开这个 CI 项目,当然我这里用的 vscode,不过都差不多了。

打开 vscode 的终端,或者 cmd 都可以,只要可以跑命令行,启动 PHP 的内置服务器就行,确保你已经把 php 添加进了你的环境变量,在项目的根目录,就是 index.php 所在的目录下键入:php -S localhost:8000

 

OK,在浏览器中访问一下 http://localhost:8000 ,你就会看到 CodeIgniter Welcome Page :

如果你不想使用 PHP 内置 Web Server,你扔然可以使用 apache 或者其他的 Web Server 进行启动项目。

FIRBASE/PHP-JWT

首先,需要找到一个 PHP 的 JWT 轮子(package),这样我们只需要将这个轮子融入到 CI 项目中就可以直接使用了。

1. 访问 https://jwt.io ;

2. 点击 Libraries 导航,下面列出的就是各个语言所写的相关轮子;

3. CTRL + F,在当前页面中直接搜索“php”,找到 star 数最高的 firbase/php-jwt

4. 前往 https://github.com/firebase/php-jwt ,阅读下 README,对它有个大致了解。

PHP-JWT 除了可以直接通过 composer 安装,也可以将它的源码直接下载下来。

https://github.com/firebase/php-jwt/tree/master/src 这里有4个 php 文件,将它们下载或复制,放到 application/libraries/ 中:

由于我们不是通过 composer 安装的,所以在 JWT.php 中,我们需要手动去 require 一下另外3个文件:

除此之外,jwt 也需要给与一个密钥用于生成 token 值,既然这是一个配置,那么我们就在 CI 的配置文件目录 application/config/ 中创建配置文件:jwt.php 。

CODEIGNITER-RESTSERVER

https://github.com/chriskacerguis/codeigniter-restserver 这是专为 CI 所造的 restserver package,加入它之后,可以很方便的接收或者处理 GET、POST、PUT、DELETE 这类请求。

这个源码其实就是一个加入 RestServer 后的 CI 项目,它的实际源码总共有4个:

1. REST_Controller,RestServer 的主控制器,你需要将自己编写的业务控制器继承它,就和继承 CI_Controller 一样;

2. Format,用于格式化响应数据,可以格式化为 json、array、csv、html、php、xml,默认为 json;

3. rest,它是 RestServer 的配置文件,类似 CI 中的大部分配置文件;

4. rest_controller_lang,它是 RestServer 的国际化配置项,里面包含了10来种语言,这里我们暂时只选择 english。

和 PHP-JWT 一样,将它们分别放入对应的目录中:

它没有一个非常详细的文档,但是有一个简单的使用教程:https://code.tutsplus.com/tutorials/working-with-restful-services-in-codeigniter–net-8814

不过源码中的注释非常非常的详细,总的来讲还是很容易就能理解的。

基础表结构

为了真实的模拟 HTTP 请求,以及实际的业务场景,现在我们来建一个非常简单的 todos 表:

建表后,别忘了在 application/config/database.php 中填入你当前的数据库相关配置。


我们已经在 CI 中加入了 php-jwt、codeigniter-restserver,并建好了数据库表、配置了数据库链接。

Cool,所有准备工作已经就绪了,接下来,将模拟具体的业务场景:

1. 用户登录,服务端校验账户和密码,成功则返回当前这个用户的 json web token;

2. 用户可以对 todo 表进行 CRUD,在 CRUD 操作时,校验 json web token 是否合法;

源码示例

JWT-RESTfull-IN-CI-Tutorial

模拟业务场景

上面,我们已经做足了准备工作,并拟定了具体的业务场景:

1. 用户登录成功,生成 TOKEN;

2. 客户端每一次对 TODO 模型进行 CRUD 操作时,都会携带 TOKEN;

3. 服务端会校验 TOKEN 合法性,给予响应请求的返回及数据库操作。

在接下来的具体编码中,不会有表单验证、注册那些逻辑,因为本文只是用于描述如何将 CI 集成为一个 JWT RESTfull API Repo。

定义模型

application/modles/User_model.php

User 模型中,一个简单的 login 方法用于对比账号密码是否正确,我们仅仅只是模拟一下 HTTP 请求进行了真实的数据库操作:

由于没有写注册逻辑,你应该在数据库中提前增加一条用户数据,如:

application/models/Todo_model.php

Todo 模型中,新增、删除、修改、查询单条记录、查询全部记录等操作:

Authorization 辅助类

由于生产 、验证 TOKEN 来自 JWT 类中的方法,为了能更方便的使用 JWT 类,我们可以在 CI 中封装自己的“辅助类”,一般 CI 将自定义的辅助类放在 application/helpers/ 中。

在这个辅助类中,引入 JWT,并且在 Authorization 类中封装了两个方法:

1. func validateToken:用于校验 TOKEN 的合法性;

2. func generateToken:用于生产 TOKEN;

Autoload 配置项

为了能更方便的使用数据库,而不用频繁的在控制器构造函数中书写类似 $this->load>library('database') 这样的代码,在 CI 中,我们可以将需要自动加载的特定 library、helper 等直接配置进 autoload 中。

Auth 控制器

准备了这么多,是时候写第一个控制器了,完成我们的场景一:客户端传递 POST 请求,服务端通过 username & password 参数,并校验参数合法性,生产 TOKEN,并返回给客户端。

接下来,我们需要在客户端中模拟这个“获取TOKEN”的 POST 请求。

打开某个专门用于测试接口的工具,例如 Postman,我这里用的 apizza :http://apizza.cc/

和上一篇一样,我们使用 php -S localhost:8000,在根目录下键入该命令,将项目运行起来后,在 apizza 中模拟我们这次的请求:

如果客户端传入的账户密码不存在,按照 Restfull 约定,服务端应该返回状态码为 401 Unauthorized:

Todo 控制器

该控制器会给予针对 Todo 模型的 CURD 操作的 API,通常服务端的 API URL 看起来应该像是这样的 : http://example.com/api/,CI 升级至 3.* 版本后控制器便能支持多级目录结构,现在我们来创建 Todo 控制器:

4个方法名分别对应了 GETPOSTPUTDELETE 这四种请求方式。

1. POST 请求

todo 表现在仍然是一张空表,因此,我们从 POST 请求开始,这个请求通常用来创建资源:

创建成功,接口将会返回 200 状态码,并将新创建的 todo 记录作为返回数据,现在我们发出几次请求,让 API 为我们在数据库中插入3条记录:

2. GET 请求

现在表中有了3条记录,编写 GET 请求来进行获取资源,服务端查看 URL 中是否有 id 参数,如果有则返回该 id 的单条数据,若没有,则返回全部数据,当然这个示例并没有校验 id 的合法性,也没有处理 404 的错误,实际开发你扔需要填补这些逻辑:

单条记录:

全部记录:

3. PUT 请求

PUT 通常用来修改某个指定的资源:

4. DELETE 请求

DELETE 用于删除指定的资源:

钩子函数

至此,我们全部的 API 编写完毕。

接下来,也是最后一步,我们还需要加入钩子函数,在 API 相关控制器调用方法之前,验证请求头是否包含 TOKEN,并在钩子函数中校验其合法性。

1. 首先,我们需要再次打开 application/config/config.php,开启 hooks

2. 指定 hooks

CI 总共有 7 种钩子,这里我们选择 post_controller_constructor,它会在你的控制器实例化之后立即执行,控制器的任何方法都还尚未调用。我们仍然需要在钩子配置中指定我们将要使用的自定义钩子类以及执行的函数名称:

3. 编写 ApiAuthHook

保护路由

当我们再次访问任意一个 API 请求时,服务端会回应一个 400 的 Error Code:

还记得第一个 auth/token/ 的 POST 请求吗?这个请求服务端返回了 TOKEN。

现在我们在请求头部加入 Authorization,并将其的值设置为 TOKEN:

Cool!接口正常返回了全部数据!

为什么在 TOKEN 值前面加入 lovchun.com?

前端需要通过 cookie 或者 localstorage 来存储 TOKEN,以此来保存调用接口的凭据。

试想一下,如果你的前端工程需要对接多个 API Server,通过什么来标识 TOKEN 分别对应着哪个 Server ?

将 Authorization 的值用“唯一标识”+“一个英文空格”+“TOKEN”来存储,服务端校验时,通过搜索该“唯一标识”的 Authorization 来获取 TOKEN(当然这个标识你完全可以自定义):


如果你是以 Apache 或其他 Web Server 启动项目,Apache 会过滤掉请求头中的 Authorization 字段!

请在根目录下的 .htaccess 文件中进行修改,让你的 Apache 能正常接收 Authorization:

噢!评论已关闭。