1. 程式人生 > >VUE+PostgreSQL+PostgREST實現使用者許可權安全分級

VUE+PostgreSQL+PostgREST實現使用者許可權安全分級

                                                                                                    預計閱讀時間:5分鐘

目錄直通車

前言

一、如何實現許可權驗證?

1、 後臺JWT生成key

 (1) 新增使用者 (Add a Trusted User)

(2) 加密處理(Make a Secret)

(3) 制定token(Sign a Token)

(4) HTTP請求

(5) 設定token的到期時間

2、 前臺與後臺結合實現

這樣真的安全嗎,如果請求被偽造怎麼辦?


前言

最近在做一個工廠的專案,在這個專案裡面需要給使用者設定一些許可權,比如說普通員工只能錄入資料不能修改、普通管理員可以檢視和修改、超級管理員可以給其他使用者設定有哪些許可權。以下內容是我們團隊完成許可權驗證之後的濃縮總結。PostgREST不知道是啥的話,還是

點選這裡補腦吧!(官方文件實在看不懂的話.......關於PostgREST的中文文件,我們團隊已翻譯處理,後續也會放在文末分享給大家。)

一、如何實現許可權驗證?

(參考PostgREST官方文件JWT部分:http://postgrest.org/en/v5.1/auth.html#jwt-generation如果下面的方案解決不了您的問題請參考其它方案請回來參考http://postgrest.org/en/v5.1/tutorials/tut1.html#tutorial-1-the-golden-key

這個專案的驗證機制的核心是在後臺生成一個帶有許可權的key,前臺只是負責傳送key與後臺的key比對

,我不想誤導大家,因為我之前被別人的文章誤導之後久久不能釋懷......,所以請看下方原話:

客戶端使用JSON Web Tokens通過API進行身份驗證。這些是JSON物件,使用僅為我們和伺服器所知的密碼進行加密簽名。由於客戶端不知道密碼,因此無法篡改其令牌的內容。PostgREST將檢測偽造的令牌並拒絕它們。

那麼問題來了,如果有人抓資料包,豈不是很容易就什麼都看到了?所以需要加密。

1、 後臺JWT生成key

這個key分為三部分,前兩個部分系統生成,在第三個secret的部分。請注意這裡指的不是使用者的密碼,當時我看了一些博文導致我以為token寫死的不能變。然而,這個secret的部分是自己可以隨意放入的字串,這樣的加密方式可以說是非常安全。如果您已經明白了,看完下面這張圖就可以直接跳過了。

具體實現

(原文連結:http://postgrest.org/en/v5.1/tutorials/tut1.html#step-1-add-a-trusted-user

 (1) 新增使用者 (Add a Trusted User)

在PostgreSQL資料庫中建立了一個web_anon角色,用於執行匿名Web請求。讓我們todo_user為使用API,進行身份驗證的使用者呼叫一個角色。此角色將有權賦予許可權列表執行任何操作。

//建立角色不允許登陸
create role todo_user nologin;    
//賦予角色與postgres使用者	
grant todo_user to postgres;	
 //schema api允許todo_user查詢該Schema下的物件
grant usage on schema api to todo_user;   
 //單表賦予todo_user角色對api.todos表所有許可權
grant all on api.todos to todo_user;     
//賦予todo_user 對於當前api下的所有表的所有許可權
//grant select on ALL tables in schema api to web_anon ;   
//查詢此表序列號的許可權也就是 序列號自動增長的許可權
grant usage, select on sequence api.todos_id_seq to todo_user;  

(2) 加密處理(Make a Secret)

客戶端使用JSON Web Tokens通過API進行身份驗證。這些是JSON物件,使用僅為我們和伺服器所知的密碼進行加密簽名。由於客戶端不知道密碼,因此無法篡改其令牌的內容。PostgREST將檢測偽造的令牌並拒絕它們。

讓我們建立一個密碼並將其提供給PostgREST。想想一個很好的長的,或使用工具來生成它。您的密碼長度必須至少為32個字元

我們的伺服器是:Linux 7

[[email protected] ~]# openssl rand 32 -base64

得到下面這串加密後的字串:qHH/CeK+w3gqSOZjZJyuon4n7ptaQ+2TarNh7r7BYKM=

 接著開啟 tutorial.conf 檔案,把這串加密的字串新增一行寫進去。

# PASSWORD MUST BE AT LEAST 32 CHARS LONG
# add this line to tutorial.conf:

#jwt-secret = "<the password you made>"
jwt-secret = "qHH/CeK+w3gqSOZjZJyuon4n7ptaQ+2TarNh7r7BYKM="

#如果啟用了secret base64 encoded 
#請把下面設定為ture預設為false 本例項中設定的
#secret-is-base64 = true

然後重啟PostgREST伺服器,一定不要忘記了。

(3) 制定token(Sign a Token)

在JWT的官網建立一個會話測試:https://jwt.io

(4) HTTP請求

現在回到伺服器終端,讓我們curl來新增一個行記錄。該請求將包含一個包含身份驗證令牌的HTTP標頭。

#export TOKEN="<paste token here>"
export TOKEN = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoidG9kb191c2VyIn0.8qw7X2-98Gaua0d5AljE8qaBWd-LFBlCdLVQ5hOnNyA"
curl http://localhost:3000/todos -X POST \
     -H "Authorization: Bearer $TOKEN"   \
     -H "Content-Type: application/json" \
     -d '{"task": "learn how to auth"}'

 緊接著通過一個patch請求將done設定為true。

curl http://localhost:3000/todos -X PATCH \
     -H "Authorization: Bearer $TOKEN"    \
     -H "Content-Type: application/json"  \
     -d '{"done": true}'

伺服器端完成配置後。在postgREST裡傳送一個如下的json包請求給伺服器測試一波。

curl http://localhost:3000/todos
[
  {
    "id": 1,
    "done": true,
    "task": "finish tutorial 0",
    "due": null
  },
  {
    "id": 2,
    "done": true,
    "task": "pat self on back",
    "due": null
  },
  {
    "id": 3,
    "done": true,
    "task": "learn how to auth",
    "due": null
  }
]

(5) 設定token的到期時間

原文如下:

Currently our authentication token is valid for all eternity. The server, as long as it continues using the same JWT password, will honor the token.

It’s better policy to include an expiration timestamp for tokens using the exp claim. This is one of two JWT claims that PostgREST treats specially.

目前token永久有效,只要伺服器繼續使用相同的JWTSecret,它就會使用相同的token,所以就希望能夠設定這個token到期的時間,需要使用exp來宣告時間戳給這個token。

現在在資料庫執行下面這條命令來設定到期時間:

select extract(epoch from now() + '5 minutes'::interval) :: integer;

再回到傳送https://jwt.io 以下payload:

{
  "role": "todo_user",
  "exp": <computed epoch value>
}

把之前的token複製儲存到一個新的變數裡面,便於複製之後重新向伺服器傳送請求作為對比。

as $$
begin
  if current_setting('request.jwt.claim.email', true) =
     '[email protected]' then
    raise insufficient_privilege
      using hint = 'Nope, we are on to you';
  end if;
end
$$;

接下來在tutorial.conf的檔案裡面新增下面一行指定新功能

pre-request = "auth.check_token"

完成之後,請不要忘記重啟PostgREST。下面驗證一下之前儲存下來的token。

# 這個可以正常請求

curl http://localhost:3000/todos \
     -H "Authorization: Bearer $TOKEN"

# 這個請求失敗

curl http://localhost:3000/todos \
     -H "Authorization: Bearer $WAYWARD_TOKEN"

失敗之後,伺服器會返回以下資訊:

{
  "hint": "Nope, we are on to you",
  "details": null,
  "code": "42501",
  "message": "insufficient_privilege"
}

 

2、 前臺與後臺結合實現

前臺Vue無非就是route路由控制。我這裡實現的方式是,使用者每一次的操作都會做一次校驗(也就是key與伺服器的key比對),前端的話可以減輕工作量,而且也很安全。

這樣真的安全嗎,如果請求被偽造怎麼辦?

這個key分為三個部分,有兩個部分是寫死的,secret這個部分可以隨機給,然後組合成為一段字串。所以,在使用者登入的時候才給使用者生成一個他對應許可權的key,然後銷燬。每一次登入和每一次操作都會重新生成一次key,每一次都會與後臺的key比對。

原始碼的話,一般我都會免費分享給大家,但考慮到同某央企工廠簽過保密協議,這裡就不提供給大家了,還望見諒。

PostgREST中文參考文件 ,提取碼: rnbn