1,public /index.php 入口文件
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2016 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
// [ 应用入口文件 ]
//处理跨域Options预检请求
if($_SERVER['REQUEST_METHOD'] == 'OPTIONS'){
//允许的源域名
header("Access-Control-Allow-Origin: *");
//允许的请求头信息
header("Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept, Authorization");
//允许的请求类型
header('Access-Control-Allow-Methods: GET, POST, PUT,DELETE,OPTIONS,PATCH');
exit;
}
// 定义应用目录
define('APP_PATH', __DIR__ . '/../application/');
// 加载框架引导文件
require __DIR__ . '/../thinkphp/start.php';
解决跨域问题
使用了路由,说白了就是将 url 和 module/controller/action 对应起来!
我们要继续梳理, token的工具类:
里面核心代码就是生成token ,还有一个通过token 获取userId 的操作
用到的类库,放入到这个模块中了,vendor 扩展目录模块,验证码类,分页的扩展模块都放这里! 通过composer 安装
<?php
namespace tools\jwt;
use Lcobucci\JWT\Builder;
use Lcobucci\JWT\Parser;
use Lcobucci\JWT\Signer\Hmac\Sha256;
use Lcobucci\JWT\ValidationData;
/**
* Created by PhpStorm.
* User: asus
* Date: 2019/4/5
* Time: 13:02
*/
class Token
{
// config
private static $_config = array(
'audience' => 'http://www.16zy8.com',
'id' => '3f2g57a92aa',
'sign' => 'pinyougou',
'issuer' => 'http://www.16faka.xyz',
'expire' => 3600*24
);
//生成token
public static function getToken($user_id){
//签名对象
$signer = new Sha256();
//获取当前时间戳
$time = time();
//设置签发人、接收人、唯一标识、签发时间、立即生效、过期时间、用户id、签名
$token = (new Builder())->issuedBy(self::$_config['issuer'])
->canOnlyBeUsedBy(self::$_config['audience'])
->identifiedBy(self::$_config['id'], true)
->issuedAt($time)
->canOnlyBeUsedAfter($time-1)
->expiresAt($time + self::$_config['expire'])
->with('user_id', $user_id)
->sign($signer, self::$_config['sign'])
->getToken();
return (string)$token;
}
//从请求信息中获取token令牌
public static function getRequestToken()
{
if (empty($_SERVER['HTTP_AUTHORIZATION'])) {
return false;
}
$header = $_SERVER['HTTP_AUTHORIZATION'];
$method = 'bearer';
//去除token中可能存在的bearer标识
return trim(str_ireplace($method, '', $header));
}
//从token中获取用户id (包含token的校验)
// 只要token不正确或者过期都会返回Null, 通过正确返回userID
public static function getUserId($token = null)
{
$user_id = null;
// 从bearer 中取出token,若有的话,则放行
$token = empty($token)?self::getRequestToken():$token;
// 有token,则执行该方法
if (!empty($token)) {
//为了注销token 加以下if判断代码
$delete_token = cache('delete_token') ?: [];
if(in_array($token, $delete_token)){
//token已被删除(注销)
return $user_id;
}
$token = (new Parser())->parse((string) $token);
//验证token
$data = new ValidationData();
$data->setIssuer(self::$_config['issuer']);//验证的签发人
$data->setAudience(self::$_config['audience']);//验证的接收人
$data->setId(self::$_config['id']);//验证token标识
if (!$token->validate($data)) {
//token验证失败
return $user_id;
}
//验证签名
$signer = new Sha256();
if (!$token->verify($signer, self::$_config['sign'])) {
//签名验证失败
return $user_id;
}
//从token中获取用户id
$user_id = $token->getClaim('user_id');
}
return $user_id;
}
}
有了 验证码类,具体使用:
访问下看看
代码没有问题,
我们看下baseapi
<?php
namespace app\adminapi\controller;
use think\Controller;
class BaseApi extends Controller
{
//不需要验证token 的列表
protected $no_login = ['login/captcha', 'login/login','index/index'];
//控制器的初始化方法(和 直接写构造方法 二选一)
protected function _initialize()
{
//实现父类的初始化方法,空方法
parent::_initialize();
//初始化代码
//处理跨域请求
//允许的源域名
header("Access-Control-Allow-Origin: *");
//允许的请求头信息
header("Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept, Authorization");
//允许的请求类型
header('Access-Control-Allow-Methods: GET, POST, PUT,DELETE,OPTIONS,PATCH');
try{
//登录检测
//获取当前请求的控制器方法名称
$path = strtolower($this->request->controller()) . '/' . $this->request->action();
if(!in_array($path, $this->no_login)){
//需要做登录检测
$user_id = \tools\jwt\Token::getUserId();
if(empty($user_id)){
$this->fail('token验证失败', 403);
}
//将得到的用户id 放到请求信息中去 方便后续使用
$this->request->get('user_id', $user_id);
$this->request->post('user_id', $user_id);
}
}catch (\Exception $e){
//token解析失败
$this->fail('token解析失败', 404);
}
}
/**
* 通用的响应
* @param int $code 错误码
* @param string $msg 错误信息
* @param array $data 返回数据
*/
protected function response($code=200, $msg='success', $data=[])
{
$res = [
'code' => $code,
'msg' => $msg,
'data' => $data
];
//原生php写法
echo json_encode($res, JSON_UNESCAPED_UNICODE);die;
//框架写法
//json($res)->send();
}
/**
* 成功的响应
* @param array $data 返回数据
* @param int $code 错误码
* @param string $msg 错误信息
*/
protected function ok($data=[], $code=200, $msg='success')
{
$this->response($code, $msg, $data);
}
/**
* 失败的响应
* @param $msg 错误信息
* @param int $code 错误码
* @param array $data 返回数据
*/
protected function fail($msg, $code=500, $data=[])
{
$this->response($code, $msg, $data);
}
}
在上面中, 我把index/index 放入了不需要验证token 的列表,所以不需要验证token
直接进入了 index方法,所以才打印出来了,当然喽,我们是为了测试用的!
若我们将index/index从 不需要验证token 的列表 移除,则会继续验证token 的逻辑
类似的思路,vue 的路由控制, beforeEach 方法中,为每个路由添加meta 属性作为标记