PureJS (6.4):利用 proxy 对象实现权限控制和数据校验
PureJS (6.4):利用 proxy 对象实现权限控制和数据校验
利用上一篇文章提到的 proxy 对象,我们还可以实现更多实用的功能。比如本文将探讨的权限控制和数据校验。
权限控制的思路是截获对 page.* 和 api.* 的调用,并利用 session 中记录的用户角色信息进行权限检查;
数据校验还将用到之前的客户端与服务器端共用代码的功能,对数据进行双重检查,以防恶意攻击。
接下来就让我们看看具体的实现吧。
权限控制
这里以对 page.* 的调用为例。基本思路是:
1. 通过正则表达式 /^page./ 和 /^api./ 匹配需要拦截的方法调用
2. 获取参数中的 req (ServletHttpRequest)
3. 获取 session 中的用户角色
4. 如果用户的角色是 admin ,则显示相应页面;否则显示登陆页面
(function() {var log = pure.log("proxy.security");proxy.security = { priority: 80 };// 对 page.* 的调用进行权限控制proxy.security.page = {priority: 100,expr: /^page./,func: function(name, method, args) {// 获取方法的第二个参数,即 reqvar req = args[1];// 读取 session 中的role。返回值是 java.lang.String// 加上空字符串转为 JavaScript 中的 Stringvar role = req.session.getAttribute("user.role") + "";// 如果角色是 "admin",则显示相应页面// 否则,显示登录页面if (role === "admin") {return this[method].apply(this, args);} else {log.info("Redirect to login page.");return pure.render("login");}}}// 利用类似的方法对 api.* 的调用进行权限控制,略proxy.security.api = { ... }}());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_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 };}// 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 };}(function() {var log = pure.log("proxy.validation");proxy.validation = { priority: 60 };proxy.validation.saveUser = {priority: 100,expr: /^dbo.users.save$/,func: function(name, method, args) {// 获取验证结果var validated = validator.validateUser(args[0]);// 验证失败,抛出异常if (!validated.success) {log.info(validated.error);throw validated.error;}var data = validated.data;// 检查用户是否已经存在// 注意,这里的 this 表示 dbo 对象if (this.exists(data.name)) {var msg = "Save User Faild: User already exists.";log.info(msg);throw msg;}// 通过验证,返回所需的结果args[0] = data;return this[method].apply(this, args);}}}());$(function(){// 其他代码,略function save(user, callback) {// 获取验证结果var validated = validator.validateUser(user);// 验证失败,显示异常if (!validated.success) {$("#error").html(validated.error);return;}var data = validated.data;// 检查用户是否已经存在for (var i = 0, l = users.length; i < l; ++i) {if (users[i].name === data.name) {$("#error").html("User already exists.");return;}}callback(data);show();pure.post({ action: "users.save", params: data });}});