相关阅读:前端
完爆Facebook/GraphQL,APIJSON全方位对比解析(一)-基础功能java
完爆Facebook/GraphQL,APIJSON全方位对比解析(三)-表关联查询git
自APIJSON发布以来,不断有网友拿来和Facebook的GraphQL对比,github
甚至有很多人声称“完爆”APIJSON。数据库
然而事实正好相反,本系列博客将以大量真实依据来证实,json
APIJSON“完爆”GraphQL!后端
APIJSON的口号是:
后端接口和文档自动化,前端(客户端) 定制返回JSON的数据和结构!api
APIJSON的简介:APIJSON是一种为API而生的JSON网络传输协议。
为 简单的增删改查、复杂的查询、简单的事务操做 提供了彻底自动化的API。
能大幅下降开发和沟通成本,简化开发流程,缩短开发周期。
适合中小型先后端分离的项目,尤为是互联网创业项目和企业自用项目。服务器
经过自动化API,前端能够定制任何数据、任何结构!
大部分HTTP请求后端不再用写接口了,更不用写文档了!
前端不再用和后端沟通接口或文档问题了!不再会被文档各类错误坑了!
后端不再用为了兼容旧接口写新版接口和文档了!不再会被前端随时随地没完没了地烦了!网络
视频演示:i.youku.com/apijson
项目主页: github.com/TommyLemon/…
自动化权限控制(APIJSON特有):
GraphQL【没有】提供权限控制的功能,甚至在官方文档和源码里连如何实现的教程也几乎没有,
而仅仅说起了如何在你的【业务代码】里去【手动】实现一个【所属人】角色的权限控制。
高亮的这行代码
if (context.user && (context.user.id === post.authorId))
复制代码
就是在后端手动写的postType中,手动加的resolve函数里,加上这么一个userId关系判断。
也就只能实现当查询postType对应的表时,只有post里的authorId和来访user的id相等时,才返回查到的结果。
下文中善意地提示了你,不要写死在某个Type的resolver函数中,
而是应该封装到一个postReponsitory,里面放一个getBody的函数,内部再实现这个判断并return。
这样不只逻辑清晰,还能在别的Type中用到postType时(例如userType嵌套postType)能够复用。(PS: 这个文档中没说,我帮它说了)
但即使你花了时间去新写一个类、再新写一个函数,作了这个封装,那也只是postType能复用而已,
其它的humanType,droidType,queryType等一大堆Type不都仍是得一个个写?
https://github.com/graphql/graphql-js/blob/master/src/__tests__/starWarsSchema.js
并且当今的互联网应用中,不论是网站,仍是移动端App,稍微复杂一点的都不仅是【所属人】这么一个角色,
其中大部分,尤为是社交应用,都包含 【联系人】、【朋友圈】这两个角色。
固然,全部具备帐户登陆的应用,均可以分【已登陆】、【未登陆】这两种角色。
既然GraphQL不提供权限控制功能,那就只能本身根据每种角色一个个写了。
按照以上惟一一个官方示例,咱们对应全部角色的判断应该是:
未登陆:
if (context.user == null || context.user.id == null || context.user.id <= 0) {
return post.body;
}
return null;
复制代码
已登陆:
if (context.user && context.user.id && context.user.id > 0) {
return post.body;
}
return null;
复制代码
朋友圈:
var userId = context.user == null ? null : context.user.id;
var contactIdList = context.user == null ? null : context.user.contactIdList; //联系人id列表
if ((userId && userId === post.authorId) || (contactIdList && contactIdList.indexOf(post.authorId) >= 0)) {
return post.body;
}
return null;
复制代码
联系人:
var contactIdList = context.user == null ? null : context.user.contactIdList; //联系人id列表
if (contactIdList && contactIdList.indexOf(post.authorId) >= 0) {
return post.body;
}
return null;
复制代码
所属人:
if (context.user && (context.user.id === post.authorId)) {
return post.body;
}
return null;
复制代码
仅仅用GraphQL实现查询postType这一个Type对应的角色权限控制,竟然就要写这么多判断代码!
假设咱们数据库有20张表(实际很轻量级的应用才只有这么少的表),对应写了20个Type,那就是 20*5 = 100 个判断!!!
仅仅是判断角色权限的代码就至少有 20*(4 + 4 + 6 + 5 + 4) = 460 行!!!
而APJSON提供了自动化的权限控制,能够细分到 每张表、每行记录、每种角色、每种操做 的控制粒度!
并且每张表只须要写3行代码就能配置各类角色的增删改查的权限!
咱们用APIJSON来操做一张表,例如用户表User,代码写3行就够了:
//注册表并添加权限,用默认配置
@MethodAccess
public class User {
//内容通常仅供表字段说明及Android App开发使用,服务端不用的可不写。
}
//DemoVerifier内添加权限
ACCESS_MAP.put(User.class.getSimpleName(), getAccessMap(User.class.getAnnotation(MethodAccess.class)));
复制代码
或者能够再定制下POST请求的角色权限:
@MethodAccess(
POST = {UNKNOWN, ADMIN} //只容许未登陆角色和管理员角色新增User,默认配置是 {LOGIN, ADMIN}
)
public class User {}
复制代码
而后运行下Server工程就能够请求了:
URL:http://apijson.cn:8080/get
请求:
{
"User": {
"id": 82001
}
}
复制代码
返回:
{
"User": {
"id": 82001,
"sex": 0,
"name": "Test",
"tag": "APIJSON User",
"head": "http://static.oschina.net/uploads/user/19/39085_50.jpg",
"contactIdList": [
82004,
82021,
70793
],
"pictureList": [
"http://common.cnblogs.com/images/icon_weibo_24.png"
],
"date": "2017-02-01 19:21:50.0"
},
"code": 200,
"msg": "success"
}
复制代码
复制代码
咱们再试试APIJSON的自动化权限控制到底 能不能达到指望、会不会被绕过 吧。
查询用户开放信息User:
/get/{"User":{"id":38710}}
请求成功:
{
"User": {
"id": 38710,
"sex": 0,
"name": "TommyLemon",
"tag": "Android&Java",
"head": "http://static.oschina.net/uploads/user/1218/2437072_100.jpg?t=1461076033000",
"contactIdList": [
82003,
82005,
90814,
82004,
82009,
82002,
82044,
93793,
70793
],
"pictureList": [
"http://static.oschina.net/uploads/user/1218/2437072_100.jpg?t=1461076033000",
"http://common.cnblogs.com/images/icon_weibo_24.png"
],
"date": "2017-02-01 19:21:50.0"
},
"code": 200,
"msg": "success"
}
复制代码
查询用户隐私信息Privacy:
/get/{"Privacy":{"id":38710}}
请求失败,无GET权限:
{
"Privacy": {
"id": 38710
},
"code": 401,
"msg": "Privacy 不容许 UNKNOWN 用户的 GET 请求!"
}
复制代码
看下源码:
@MethodAccess(
GET = {},
GETS = {OWNER, ADMIN}
)
public class Privacy {}
复制代码
很明显,get是不容许的,能够用gets,但也必须是OWNER, ADMIN这2种角色中的一个。
URL: http://apijson.cn:8080/gets/
请求:
{
"Privacy": {
"id": 38710
},
"tag": "Privacy"
}
复制代码
仍然失败,由于没登陆,未登陆是UNKNOWN用户,这里自动补全为OWNER:
{
"Privacy": {
"id": 38710
},
"tag": "Privacy",
"code": 407,
"msg": "未登陆,请登陆后再操做!"
}
复制代码
那咱们能不能伪造一下角色骗过APIJSON呢?试试看:
{
"Privacy": {
"id": 38710,
"@role": "circle"
},
"tag": "Privacy"
}
复制代码
仍是同样的报错:未登陆。
{
"Privacy": {
"id": 38710,
"@role": "circle"
},
"tag": "Privacy",
"code": 407,
"msg": "未登陆,请登陆后再操做!"
}
复制代码
好吧,我登陆后再试,新的报错:
{
"Privacy": {
"id": 38710,
"@role": "circle"
},
"code": 401,
"msg": "Privacy 不容许 CIRCLE 用户的 GETS 请求!"
}
复制代码
为何呢?角色不符合OWNER, ADMIN这2种角色中的一个。
那换成OWNER角色呢?
{
"Privacy": {
"id": 38710,
"@role": "owner"
},
"tag": "Privacy"
}
复制代码
继续报错:
{
"Privacy": {
"id": 38710,
"@role": "owner"
},
"code": 401,
"msg": "id = 38710 的 Privacy 不容许 OWNER 用户的 GETS 请求!"
}
复制代码
换成后端没有的角色呢?
{
"Privacy": {
"id": 38710,
"@role": "test"
},
"tag": "Privacy"
}
复制代码
报错,角色不存在:
{
"Privacy": {
"id": 38710 ,
"@role": "test"
},
"code": 406 ,
"msg": "角色 test 不存在!只能是[UNKNOWN,LOGIN,CONTACT,CIRCLE,OWNER,ADMIN]中的一种!"
}
复制代码
再试试 "@role": "admin" :
{
"Privacy": {
"id": 38710,
"@role": "admin"
},
"tag": "Privacy"
}
复制代码
仍然报错:
{
"Privacy": {
"id": 38710,
"@role": "admin"
},
"code": 406,
"msg": "角色设置错误!不容许在写操做Request中传 Privacy:{ @role:admin } !"
}
复制代码
管理员角色是只能在服务器内部设置的,不容许传哦。
因此,按照Privacy的权限配置,前端只有用OWNER角色去查当前已登陆帐户(id=82001)的Privacy:
{
"Privacy": {
"id": 82001,
"@role": "owner" //Request表中配置了自动补全,可不写
},
"tag": "Privacy"
}
复制代码
才会返回正确的结果:
{
"Privacy": {
"id": 82001,
"certified": 1,
"phone": 13000082001,
"balance": 8781.46
},
"code": 200,
"msg": "success"
}
复制代码
注: 以上APIJSON请求均可以在 http://apijson.org 在线工具上测试
总结
GraphQL没有提供权限控制的功能,须要后端针对每张表对应的Type去对应各类角色一个个手写大量判断代码!
而APJSON提供了自动化的权限控制,能够细分到 每张表、每行记录、每种角色、每种操做 的控制粒度!
并且每张表只须要写3行代码就能配置各类角色的增删改查的权限!以上测试用例也说明了它不但配置简单还很可靠!
APIJSON,让后端接口和文档自动化,前端(客户端) 定制返回JSON的数据和结构!
创做不易,右上角点Star支持下吧,很是感谢^_^