相關閱讀:前端
完爆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支持下吧,很是感謝^_^