GraphQL與認證

GraphQL與認證

很多人會問GraphQL怎么認證和授權。最終的答案是GraphQL只是一個查詢語言和認證之類的沒什么關系,每一個應用都可以有自己的實現方法。但是,我們還是來深入聊聊這個問題。

大局上看

基本上,有三種情況會發生:

  1. 已經登錄的用戶發出GraphQL查詢,未登錄的用戶不可以。認證在非GraphQL節點完成。
  2. 所有用戶都可以發出GraphQL查詢,未登錄用戶可以使用其中的一個子集。認證在非GraphQL節點完成。
  3. 所有用戶都可以發出GraphQL查詢,認證就由GraphQL節點完成。

第一種情況可能是普遍存在的。你已經有一個REST或者RPC節點,只有認證成功的用戶可以訪問,添加/graphql非常的簡單。不好的地方是,你的客戶端不得不處理GraphQL和非GraphQL兩種情況。這可能是一筆技術債。

第二種情況是第一種項目進化以后的結果。最終前端代碼只使用GraphQL,只不過久經考驗的認證節點還會留著。

第三種情況一般是一個全新的后端會有的形態,盡量避免處理非GraphQL節點。我(作者)還沒有見過這樣形態的服務端。

非GraphQL節點的處理機制

非GraphQL節點,我是指cookies、JSON和web tokens,或者HTTP基本認證。基本上無論何種方式,你的server都可以通過認證一個用戶、一個請求并最終把數據傳輸給你的resolver。

這里是一個使用express-graphql和cookies是例子(從他們的例子里結果來的):

var session = require('express-session');
var graphqlHTTP = require('express-graphql');
var MySchema = require('./MySchema');
var app = express();

app.use(session({ secret: 'secret', cookie: { maxAge: 60000 }}));

app.use('/graphql', graphqlHTTP((request) => ({
  schema: MySchema,
  rootValue: { session: request.session },
  graphiql: truem
})));

在express里,請求在一個比GraphQL路由更早的中間件處理了。之后,請求才會到達GraphQL代碼。我們知道請求是從哪里來的。我們甚至都可以在請求到達GraphQL代碼以前,把請求重定向到登錄頁面。

下面的例子使用了express-session,但是處理的原則和express-jwt差不多。在GraphQL層面上,你的schema代碼會是這樣的:

new GraphQLObjectType({
  name: 'Secrets',
  fields: {
    bigSecret: {
      type: GraphQLString,
      resolve(parentValue, _, { rootValue: { session } }) {
        return getBigSecret(session);
      }
    }
  }
});

只要能取到session,那么用戶就可以訪問其他相關的資源了。或者,如果session不存在,那么你按照你的設計拋出錯誤或者實現其他的處理。

關鍵是rootValue并沒有在我們的GraphQL模式中定義為一個公開的字段或者參數,我們不信任客戶端直接發送過來的數據,所以它是由server的其他代碼注入的。

使用GraphQL時的實現機制

但是我們要完全的使用GraphQL呢?以上的方法可以在使用了express-graphql的時候使用。但是無法遷移到其他的實現里。

在少數的例子里,Facebook談到了 concept of a viewer field。主要的思想是你的應用的數據和誰訪問相關,所以全部的其他字段的數據都嵌入到里面。實際情況是,不可能所有的數據都和訪問者相關。但是這么做的話,你可以有改變的余地。

{
  viewer {
    name
    friends {
      name
    }
    getProfile(id: String!) {
      name
    }
  }
}

注意即使和訪問者無關的getProfile字段也放在了viewer字段里,為了以防萬一哪天要限制訪問者可以訪問的數據的時候處理起來就簡單了。

一個像Facebook一樣的APP為了保護隱私,有很多什么人可以查看什么數據的邏輯處理。即使是一個簡單的APP也不會讓用戶查看他沒有創建的數據。一個常用的方法是修改URL里的userID來查看一些私有數據,如果server不檢查用戶所有權的話。使用一個單一的viewer字段就讓所有權檢查簡單了很多。

上面的schema也可以和非GraphQL節點的認證方法一起使用。但是如果我們這么干的話呢:

{
  viewer(token: String) {
    name
  }
}

如果不是用header或者查詢參數(比如:JWT、OAuth、等),我們可以把它放在GraphQL的查詢里。你的schema的代碼可以使用JWT庫等工具直接解析傳過來的token

**注意**:永遠使用HTTPS來傳輸敏感數據。

要發出新的token,mutation就可以使用了:

mutation {
  createToken(username: String!, password: String!) {
    token
    error
  }
}

我們可以認證放在mutation里,要么返回一個token要么返回一個錯誤。這樣前端就可以把token存起來在之后的請求里使用了。

譯自:https://medium.com/the-graphqlhub/graphql-and-authentication-b73aed34bbeb#.8sif1n1lj

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • Spring Cloud為開發人員提供了快速構建分布式系統中一些常見模式的工具(例如配置管理,服務發現,斷路器,智...
    卡卡羅2017閱讀 134,837評論 18 139
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,813評論 25 708
  • 第一章 Nginx簡介 Nginx是什么 沒有聽過Nginx?那么一定聽過它的“同行”Apache吧!Ngi...
    JokerW閱讀 32,747評論 24 1,002
  • 原文標題:GraphQL vs. REST Two ways to send data over HTTP: W...
    iamfanny閱讀 19,221評論 4 29
  • 我們從虛無中來,又要回到虛無中去,虛無才是我們的家,可是以虛無為家,不正是無家可歸了嗎?從虛無到虛無,人類經過一段...
    六月雨JuneRain閱讀 284評論 0 0