9.1 令牌.
之前我们做的所有接口都没有权限控制,所有用户都可以调用.
但是有些接口能公开访问.有些接口就不能公开访问.这个权限怎么做?
我们是用令牌管理我们的用户身份的.登录就是获取一个令牌.用户在每一次api请求都需要携带它的令牌.
下面我们逐步学习令牌的设计以及原理.
1.令牌
上面的流程是一个通用的设计模式.
2.image.png
Auth代表身份 Token也有过期时间 不是有Token就能获取下单接口,还有验证身份..........
(1)验证Token是否合法
(2)验证是否Token有效(过期没)
(3)验证Token所对应的权限
9.2 微信体系身份设计
上节是将的基础,思路,这一节是对上面的细化
因为小程序会为每一个用户生成一个Code码,因此不再需要传递账户,密码.只需将Code码传递给getToken,
在getToken方法中我们需要将Code码传递到微信服务器中,服务器会返回你2个重要的信息(openid,session_key),openid就是用户唯一的标识,不过还有别的用处,比如微信支付时候.在我们这里不需要使用session_key.同一个用户在不同的小程序内部openid是不同的.
在getToken方法下拿到Token,然后将Token存起来.于是用户身份体系就建立起来了.
然后将Token返回给客户端,让客户端每次访问都携带Token.
不建议将openid传入到客户端,因为openid安全的原因,还有openid不能改变.就不能设置它的有效期.解决方法就是生成一个令牌.
缓存实际上将Token和用户信息存储在缓存中,加快访问速度.但是不要滥用缓存.虽然缓存用起来的非常简单的,但是缓存的维护是非常麻烦的.这个远远要比数据库的维护还要麻烦.
4.image.png
缓存的好处是不用去查数据库了,直接去缓存内校验Token
9.3 开始实现Token身份权限体系
route.php
//获取Token 为什么这里要用post 因为code安全性 get参数只能放在url路径下,因此用post将参数放到body里面去.比get要好一点.但是使用抓包工具还是能查看到相应的信息.因此最安全的是https
Route::post('api/:version/token/user','api/:version.Token/getToken');
因为开始编写User模型业务逻辑就开始更加麻烦,因此我们再写一个service层.
service层很好的体现了MVC的Model层的分层概念.Service就是处理较为复杂的业务逻辑.而Model只是处理一些细粒度的单个业务逻辑.Model层不仅编写简单的业务逻辑,而且对数据库操作.实现数据表的增删改查.
Model模型定义的名字必须与数据库的表名相一致!
9.3.1 编写Token
控制层Token.php
class Token
{
//code是小程序用户都会拥有的
public function getToken($code=''){
//校验参数 去目录validate
//编写路由
(new TokenGet())->goCheck();
$ut = new UserToken();
$token = $ut->get($code);
return $token;
}
}
模型层User.php
class User extends BaseModel
{
}
Service层下UserToken.php
class UserToken
{
public function get($code){
}
}
路由route.php
//获取Token 为什么这里要用post 因为code安全性 get参数只能放在url路径下,因此用post将参数放到body里面去
Route::post('api/:version/token/user','api/:version.Token/getToken');
9.4 实现Token身份权限体系二
现在我们要通过小程序向控制层Token接口的getToken方法请求,发送code.
9.4.1写自定义的配置文件,在extra目录下的新建一个php file.名为wx
wx.php
return [
//app_id app_secret为自己小程序申请时拥有的.
'app_id' => '************',
'app_secret' => '*****************',
// %s 为占位符
'login_url' => 'https://api.weixin.qq.com/sns/jscode2session?appid=%s&secret=%s&js_code=%s&grant_type=authorization_code',
];
开始编写http请求,因为很多地方都要拥有http请求,因此将该方法写成公共方法,TP5提供了一个地方能够使TP5所有的类都使用,在application下的common.php
// 应用公共文件
/**
* @param string $url get请求的地址
* @param int $httpCode 返回状态码
* @return mixed
*/
function curl_get($url,&$httpCode = 0){
$ch = curl_init();
curl_setopt($ch,CURLOPT_URL,$url);
curl_setopt($ch,CURLOPT_RETURNTRANSFER,1);
//不做证书校验,部署在linux环境下请改为true
curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,false);
curl_setopt($ch,CURLOPT_CONNECTTIMEOUT,10);
$file_contents = curl_exec($ch);
$httpCode = curl_getinfo($ch,CURLINFO_HTTP_CODE);
curl_close($ch);
return $file_contents;
}
9.5 00:05:14
11
post请求 raw JSON
如果通过code获取openid时候出现错误40029
原因有可能 后台配置的appid 与 微信服务器工具配置的appid不是一个项目.
我认为9.1----9.8之间的所有课程是非常重要了.
讲解一登录权限,令牌的设计思想.是所有web开发都能用到的思想.
在小程序调试api的时候,如果想debug调试只需要在小程序的index.js下url: baseUrl + '/token/user',更改成 url: baseUrl + '/token/user?XDEBUG_SESSION_START=????',
getToken: function(){
//调用登录接口
wx.login({
success: function(res){
var code =res.code;
console.log('code');
console.log(code);
wx.request({
url: baseUrl + '/token/user',
data:{
code : code
},
method: 'POST',
success:function(res){
console.log(res.data);
wx.setStorageSync('token', res.data.token);
},
fail:function(res){
console.log(res.data);
}
})
}
})
},
然后会被自动进入PHPStrom下进行调试.当时小程序返回的空的token原因是在get方法下只调用了grantToken方法 但是没有接收grantToken返回的token.
9.9商品详细接口分析与初步编写
在9.1到9.8我们 实现了token 但是没有实现具体的应用
上一节我们把 token的key value存在TP5的缓存中去了.默认缓存是存在runtime目录下的cache目录
product表与product_img是一对多的关系.一个商品有多个详情,一个详情只属于一个商品.
product表与product_property也是一对多的关系.
测试发送请求的时候要看看是发送的get请求还是post请求.
记住关联模型的时候要有 return
原因有可能是请求get,但是实际请求的是post
HttpException</abbr> in App.php line 369
控制器不存在:V1
9.10
路由变量规则与分组
TP5的路由是顺序匹配的
例如
这样就不会出错 位置没问题
Route::get('api/:version/product/recent','api/:version.Product/getRecent');
Route::get('api/:version/product/:id','api/:version.Product/getOne');
Route::get('api/:version/product/by_category','api/:version.Product/getAllInCategory');
这样就出错了 因为当你访问api/:version/product/recent时候匹配的是:id
Route::get('api/:version/product/:id','api/:version.Product/getOne');
Route::get('api/:version/product/recent','api/:version.Product/getRecent');
Route::get('api/:version/product/by_category','api/:version.Product/getAllInCategory');
解决方案 我们要对api/:version/product/:id中的id号有一个限定
//商品详细 对id参数进行限定 当为整数的时候才会匹配这个路由, 第三个参数为可选参数
Route::get('api/:version/product/:id','api/:version.Product/getOne',[],['id'=>'\d+']);
路由分组
好处
1.让你少些几个url地址
2.TP5路由匹配的效率要高
//路由分组
Route::group('api/:version/product',function (){
Route::get('/:id','api/:version.Product/getOne',[],['id'=>'\d+']);
Route::get('/recent','api/:version.Product/getRecent');
Route::get('/by_category','api/:version.Product/getAllInCategory');
});
上面与下面代码等价
//商品详细 对id参数进行限定 当为整数的时候才会匹配这个路由, 第三个参数为可选参数 规则是正则表达式
Route::get('api/:version/product/:id','api/:version.Product/getOne',[],['id'=>'\d+']);
Route::get('api/:version/product/recent','api/:version.Product/getRecent');
//product分类详细
Route::get('api/:version/product/by_category','api/:version.Product/getAllInCategory');
9.11 闭包函数构建查询器
peoduct_img表中order字段是序号 序号代表一张大图从上到下123456....
一张竖长图分隔的
在product.php 控制层中查询详细 关联了product_image表 要根据product_image的字段名升序排序
public static function getProductDetail($id){
$product = self::with([
//Query
'imgs' => function($query){
$query->with(['imgUrl'])
->order('order','asc');
}
])
->with(['properties'])
// ->with(['imgs.imgUrl'])
->find($id);
return $product;
}
初看起来这种写法是比较麻烦的,但是你写多了这种方法是容易理解的.
学习技巧
有些东西不一定非要强制性现在搞明白 编写里面的小技巧内容写法很多.就像刚才我们写的,不要认为多么高深.有些时候我们不能明白某些写法,没关系.先学会怎么用它.比如下次遇见类似的这种情况.对关联模型下的模型根据字段进行排序.就可以套用这种写法.
9.12 用户收货地址 -- 通过令牌获取用户标识
现在需要编写一个全新的接口 因为之前都是查询的
现在要编写一个 新增数据 的接口.
保存用户信息的接口 需要权限,因为不能任何一个人都能保存到数据库信息.
开始编写.首先先把基础的实现,然后再利用AOP的思想将权限加上去.
image.png
这样就能避免A用户修改B用户信息,A用户只能访问自己的用户信息.
9.14 用户收货地址--模型新增和更新
model下的User.php
class User extends BaseModel
{
//如果在没有外键的一方调用一对一之间的关系 需要用hasOne 否则用belongsTo
public function address(){
return $this->hasOne('UserAddress','user_id','id');
}
public static function getByOpenId($openid){
//我们的目的是通过openid找到相应的用户
$user = self::where('openid','=',$openid)->find();
return $user;
}
}
9.14 有点不理解
9.12到9.15还是需要多看看
尤其是9.14 00:05:00这里开始
返回的状态码不预期的时候,可以自定义状态码.
//手动设置状态码
return json(new SuccessMessage(),201);
有点不懂得地方
image.png
image.png
网友评论