完爆Facebook/GraphQL,APIJSON全方位对比解析(二)-权限控制

3,274 阅读8分钟

相关阅读:

完爆Facebook/GraphQL,APIJSON全方位对比解析(一)-基础功能

 

自APIJSON发布以来,不断有网友拿来和Facebook开发的GraphQL对比,甚至不少人声称“完爆”APIJSON。

然而事实正好相反,本系列博客将以大量真实依据来证明,APIJSON“完爆”GraphQL!

 

APIJSON的口号是:

后端接口和文档自动化,前端(客户端) 定制返回JSON的数据和结构!

 

APIJSON的简介:

APIJSON是一种为API而生的JSON网络传输协议。
为 简单的增删改查、复杂的查询、简单的事务操作 提供了完全自动化的API。
能大幅降低开发和沟通成本,简化开发流程,缩短开发周期。
适合中小型前后端分离的项目,尤其是互联网创业项目和企业自用项目。

通过自动化API,前端可以定制任何数据、任何结构!
大部分HTTP请求后端再也不用写接口了,更不用写文档了!
前端再也不用和后端沟通接口或文档问题了!再也不会被文档各种错误坑了!
后端再也不用为了兼容旧接口写新版接口和文档了!再也不会被前端随时随地没完没了地烦了!

特点功能

在线解析

  • 自动生成文档,清晰可读永远最新
  • 自动生成请求代码,支持Android和iOS
  • 自动生成所有JavaBean,一键下载
  • 自动管理与测试接口用例,一键共享
  • 自动校验与格式化JSON,支持高亮和收展

对于前端

  • 不用再向后端催接口、求文档
  • 数据和结构完全定制,要啥有啥
  • 看请求知结果,所求即所得
  • 可一次获取任何数据、任何结构
  • 能去除重复数据,节省流量提高速度

对于后端

  • 提供通用接口,大部分API不用再写
  • 自动生成文档,不用再编写和维护
  • 自动校验权限、自动管理版本
  • 开放API无需划分版本,始终保持兼容
  • 支持增删改查、模糊搜索、正则匹配、远程函数等

视频演示:http://i.youku.com/apijson

 

 

 

 

 

自动化权限控制(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&amp;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.cn 在线工具上测试

 

 

 

总结

GraphQL没有提供权限控制的功能,需要后端针对每张表对应的Type去对应各种角色一个个手写大量判断代码!

而APJSON提供了自动化的权限控制,可以细分到 每张表、每行记录、每种角色、每种操作 的控制粒度!

而且每张表只需要写3行代码就能配置各种角色的增删改查的权限!以上测试用例也说明了它不但配置简单还很可靠!

 

 

APIJSON,让后端接口和文档自动化,前端(客户端) 定制返回JSON的数据和结构!

 

创作不易,右上角点Star支持下吧,非常感谢^_^

github.com/TommyLemon/…