资源权限控制的选择用哪一个好

公孙二狗 发布于 2016/08/31 23:51
阅读 589
收藏 1

在权限控制中有两个粒度需要控制

  1. URL 级别: 可以使用 Spring Security 来实现
  2. 资源级别: 用户访问具体的资源,例如普通用户只能删除自己的资源 (删除的 URL 的 pattern 在 Spring Security 来说是同一个),这个级别的权限控制只能写代码实现

下面的问题是关于资源级别的权限控制,例如需要删除文档:

  1. 方法一(请看 Controller): 一条 SQL 语句中执行 SQL,删除同时满足用户 ID 和文档 ID 的文档,缺点是管理员不能用此方法删除用户的文档,因为用户 ID 不是管理员的,管理员的操作需要用另外的 URL 和方法
  2. 方法二(请看 Controller): 先判断登陆用户是否管理员,或者这个资源属于登陆的用户,然后删除,缺点是有可能会多执行一条 SQL,优点是管理员可以用这个方法删除普通用户的资源

问题:

如果是你,你会选择方法一还是方法二?

Controller

方法一
// 删除 doc id 为 docId 的文档
@DeleteMapping(/fileSystem/file/1/{docId})
public Object deleteDoc1(int docId) {
    int loginUserId = getLoginUserId(); // 取得登陆用户的 id

    // 一条 SQL 执行删除,如果这个 docId 不属于 loginUserId,只是不删除成功,不会造成什么错误
    // ::: 缺点是例如管理员想删除文档,需要从写一个删除的实现,URL 不同,dao 中删除的方法不通
    docDao.deleteDocByDocIdAndUserId(docId, loginUserId); 
}

方法二
// 删除 doc id 为 docId 的文档
@DeleteMapping(/fileSystem/file/2/{docId})
public Object deleteDoc2(int docId) {
    int loginUserId = getLoginUserId(); // 取得登陆用户的 id

    // 1. 管理员可以删除普通用户的文档 doc
    // 2. 普通用户只能删除自己的文档
    // ::: 缺点是很可能多执行一个 SQL
    if (isAdmin(loginUserId) || docDao.userHasDoc(loginUserId, docId)) {
        docDao.deleteDocByDocId(docId);
    }
}

数据库表 doc:
id  name     user_id
1   foo.txt  123
2   bar.txt  234

DocDAO:

// 删除用户的文档
void deleteDocByDocIdAndUserId(int id, int userId) {
    // 执行 SQL
    delete from doc where id=id and user_id=userId
}

// 删除指定 id 的文档
void deleteDocByDocId(int id) {
    // 执行 SQL
    delete from doc where id=id
}

// 文档是否属于用户
boolean userHasDoc(int userId, int docId) {
    // 执行 SQL
    int count = select count(1) from doc where id=id and user_id=userId
    return count > 0;
}







加载中
0
曾经的十字镐
曾经的十字镐

建议看下shiro,它可以吧权限控制在细粒度内,而且社区比较活跃。

公孙二狗
公孙二狗
Shiro 的细粒度仍然只能到 URL 级别,不能到资源级别,例如删除资源的 URL 都是同一个,所有普通用户都是访问这个 URL 删除他自己的资源,需要在这个 URL 的逻辑里判断是否能删除,URL 本身控制不了具体的资源
0
红薯官方
红薯官方
// 系统用户工具类
class UserHelper {

    public static String getUser(){
        return ...; // todo 获取当前的用户
    }

    public static boolean isAdminUser() {
        return getUser().isAdmin();
    }
}

// 业务控制器
class UserDocumnetManageController {

    @DeleteMapping("/fileSystem/file/{docId}")
    public void delete(int docId) {
        String username = UserHelper.getUser().getName();
        if(UserHelper.isAdmin()) {
            username = null;
        }
        
        return docDao.deleteByIdAndUsername(docId, username);
    }
}

// DAO
class DocumentDAO{

    public void deleteByIdAndUsername(int id, String username) {
        // 动态产生SQL:如果username为 null 则SQL中where不包含username的匹配
    }
}

// 另外还可以根据组织机构的结构来限定管理员的权限范围。



红薯官方
红薯官方
结合shiro更自然。
0
haoran_10
haoran_10
建议不要使用框架级别的权限控制, 了解下RBAC,使用这个思想,自己搭建一套,很简单的
公孙二狗
公孙二狗
RBAC 是基于角色的,也就是只能到 URL 级别,SpringSecurity,Shiro 都可以做到,RBAC 做不到粒度细到资源
0
SimonAt
SimonAt
关注!
0
Fatboy123
Fatboy123
登录后把角色放到session里面,就不用每次执行操作都去数据库查一次是什么角色啦?
0
554330833a
554330833a
shiro可以吗
返回顶部
顶部