PandaJS使用說明(1.7):許可權控制和資料校正

來源:互聯網
上載者:User

PandaJS 使用說明(1.7):許可權控制和資料校正

  利用上一篇文章提到的 proxy 對象,我們還可以實現許可權控制和資料校正。
  許可權控制的思路是截獲對 page.* 和 api.* 的調用,並利用 session 中記錄的使用者角色資訊進行許可權檢查;
  資料校正將重用校正代碼,在用戶端和伺服器端對資料進行雙重檢查。

許可權控制

  這裡以對 page.* 的調用為例。基本思路是:
  1. 通過Regex /^page./ 和 /^api./ 匹配需要攔截的方法調用
  2. 擷取參數中的 req (ServletHttpRequest)
  3. 擷取 session 中的使用者角色
  4. 如果使用者的角色是 admin ,則顯示相應頁面;否則顯示登陸頁面

Javascript代碼 
(function() { 
    var log = panda.log("proxy.security"); 
 
    proxy.security = { priority: 80 }; 
 
    // 對 page.* 的調用進行許可權控制 
    proxy.security.page = { 
        priority: 100, 
        expr: /^page./, 
        func: function(name, method, args) { 
            // 擷取方法的第二個參數,即 req 
            var req = args[1]; 
 
            // 讀取 session 中的role。傳回值是 java.lang.String 
            // 加上Null 字元串轉為 JavaScript 中的 String 
            var role = req.session.getAttribute("user.role") + ""; 
 
            // 如果角色是 "admin",則顯示相應頁面 
            // 否則,顯示登入頁面 
            if (role === "admin") { 
                return this[method].apply(this, args); 
            } else { 
                log.info("Redirect to login page."); 
                return panda.render("login"); 
            } 
        } 
    } 
 
    // 利用類似的方法對 api.* 的調用進行許可權控制,略 
    proxy.security.api = { ... } 
}()); 


  簡單起見,這裡僅包含了 admin 一種角色。
  除此之外,還需要建立檔案 webapp/login.html (登陸頁面) webspp/js/login.js (向伺服器發送使用者名稱和密碼的用戶端 JS ) 和 scripts/api/auth.js(登入使用者名稱和密碼驗證),具體內容請查看附件中的相應檔案。

  啟動 mongod 和 PandaJS 工程(見附件),輸入http://localhost/,將顯示登入頁面,在控制台輸出(或日誌)中也可以看到“Redirect to login page.”的提示。
  輸入使用者名稱和密碼並點擊 Sign in 之後,將顯示使用者列表。

資料校正

  首先編寫在伺服器端和瀏覽器中共用的 validator 對象:

  webapp/js/both/validator.js
Javascript代碼 
validator = {}; 
 
// 校正異常資訊 
validator.USER_INVALID = "Invalid user data."; 
validator.USER_NAME_EMPTY = "Name cannot be empty."; 
validator.USER_NAME_TOO_LONG = "Name cannot be longer than 50."; 
validator.USER_NAME_FORMAT = "Name format is not conrrect."; 
validator.USER_DESC_EMPTY = "Description cannot be empty."; 
validator.USER_DESC_TOO_LONG = "Description cannot be longer than 50."; 
 
// 檢查 user 對象的方法 
validator.validateUser = function(user) { 
    // 參數類型錯誤,可能是惡意攻擊 
    if (typeof user.name !== "string" 
            || typeof user.desc !== "string") { 
        return { success: false, error: validator.USER_INVALID }; 
    } 
 
    // name 為空白 
    if (!user.name) { 
        return { success: false, error: validator.USER_NAME_EMPTY }; 
    } 
 
    // name 過長 
    if (user.name.length > 50) { 
        return { success: false, error: validator.USER_NAME_TOO_LONG }; 
    } 
 
    // name 格式檢查 
    if (!/^[A-z][A-z0-9._]*$/.test(user.name)) { 
        return { success: false, error: validator.USER_NAME_FORMAT }; 
    } 
 
    // desc 為空白 
    if (!user.desc) { 
        return { success: false, error: validator.USER_DESC_EMPTY }; 
    } 
 
    // desc 過長 
    if (user.desc.length > 50) { 
        return { success: false, error: validator.USER_DESC_TOO_LONG }; 
    } 
 
    // 提取 name 和 desc;因為對象中可能還有其他不需要的屬性 
    var data = { name: user.name, desc: user.desc } 
    return { success: true, data: data }; 

  這段代碼在伺服器端的 proxy.validation 對象 和 瀏覽器端的 save(...) 中被用到。
  用戶端的校正是為了給使用者更快的反饋,伺服器端的校正是為了避免惡意攻擊。
  代碼實現如下:

  scripts/app/proxy/validation.js
Javascript代碼 
(function() { 
    var log = panda.log("proxy.validation"); 
 
    proxy.validation = { priority: 60 }; 
 
    // 建立或更新 user 時,檢查 user 資料 
    proxy.validation.saveUser = { 
        priority: 100, 
        expr: /^dbo.users.(add|update)$/, 
        func: function(name, method, args) { 
            var validated = validator.validateUser(args[0]); 
 
            if (!validated.success) { 
                log.info(validated.error); 
                throw validated.error; 
            } 
 
            args[0] = validated.data; 
 
            return this[method].apply(this, args); 
        } 
    }; 
 
    // 建立 user 時,檢查使用者是否已經存在 
    proxy.validation.addUser = { 
        priority: 80, 
        expr: /^dbo.users.add$/, 
        func: function(name, method, args) { 
            var user = args[0]; 
 
            if (this.exists(user.name)) { 
                var msg = "The user already exists."; 
                log.info(msg); 
                throw msg; 
            } 
 
            return this[method].apply(this, args); 
        } 
    }; 
}()); 


  webapp/js/index.js
Javascript代碼 
$(function(){ 
    // 其他代碼,略 
 
    function save(action, user) { 
        // 驗證 user 資料有效性 
        var validated = validator.validateUser(user); 
 
        if (!validated.success) { 
            $("#error").html(validated.error).show();    
            return; 
        } 
 
        // 向伺服器端發送請求 
        var req = { action: action, params: validated.data }; 
        panda.post(req, show, function(error){ 
            $("#error").html(error).show();  
        }); 
    } 
 
    function show(users) { ... } 
}); 

  可以看到,檢查輸入是否為空白和檢查輸入參數長度、格式的部分是共用的,但檢查使用者是否存在的邏輯只存在於伺服器端的 proxy 對象。
  另外,proxy 對象的 func 中 的 this 表示的是被截獲的對象,因此我們可以在 proxy.validation.saveUser 中調用 dbo.exists(name) 來檢查使用者是否已經存在。
  此外,還需要實現 dao.users.exists(name) 方法,並在 index.html 中添加對 webapp/js/both/validator.js 的引用,詳細內容請查看附件中的相應檔案。

小結

  1. 我們可以利用 proxy 對象攔截方法的調用,進行許可權和資料的檢查
  2. 我們可以將伺服器和瀏覽器端共用的代碼放在 both 目錄下
  3. proxy 對象的 func 中 的 this 表示的是被截獲的對象

 

本文出自“裴小星的部落格”
 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.