完爆Facebook/GraphQL,APIJSON全方位對比解析(二)-許可權控制

TommyLemon-GitHub發表於2018-06-05

相關閱讀:

完爆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/…

 

相關文章