【问题标题】:How to refer to predefined database entries in source code如何在源代码中引用预定义的数据库条目
【发布时间】:2015-10-16 05:09:20
【问题描述】:

在我们公司,我们讨论了如何在我们的java源代码中引用某些数据库条目。情况如下:

java web 应用程序连接到由 SQL 脚本设置的 MySQL 数据库,JPA/Hibernate 用于 ORM。在此脚本中,我们在“角色”表中插入 3 个角色(即用户可以在 Web 应用程序中拥有的角色,即用户表具有角色表的外键)。这些角色具有 SQL 脚本中给出的预定义主键/ID (BIGINT) 和名称 (VARCHAR)。这些角色不用于安全框架,而是用于业务逻辑。目前它看起来像这样:

if(user.getRole.getId()==1) {
     // user is in role A
} else if(user.getRole().getId()==2) {
    // user is in role B
} ...

由于角色必须在编译时由源代码知道(因为逻辑取决于它们),我们必须检查用户是否具有某些角色。现在的问题是如何做到这一点。我们已经讨论过:

a) 通过 ID 或名称更好地检查 b) 使用 String/Long 常量或枚举来检查相等性

to a) 我更喜欢检查 ID(因为它不太可能在我们使用脚本在数据库设置中插入 ID 时更改),角色名称更有可能在应用程序的生命周期内更改。

to b) 我更喜欢使用常量,因为我不喜欢依赖枚举索引/序数。此外,我们在这里不需要类型安全。我看到枚举的唯一优点是它很容易获取所有值,afaik 只有在常量的情况下反射才有可能。但由于我们在 DB 上定义了所有角色,因此可以在运行时从那里获取它们。

有什么建议吗?

【问题讨论】:

    标签: java mysql database enums


    【解决方案1】:

    使用您的方法,在编译时需要角色,因此从数据库中获取它们没有帮助。

    我会使用存储 id 的枚举:

    public enum Role {
         ROLE1(1), ROLE2(2), ROLE(3);
    
         private final int id;
         private Role(int id) {
             this.id=id;
         }
    
         public int getId() {
              return this.id;
         }
    }
    

    如果您想将它们与数据库条目进行匹配(例如,获取一些额外的元数据),您已经存储了匹配的 id。这使您能够从数据库角色转换为枚举角色,反之亦然。

    【讨论】:

    • with " 但是由于我们在数据库上定义了所有角色,因此可以在运行时从那里获取它们。我的意思是我们可以遍历代码中的所有角色,例如by (for Role 角色: roleService.findAll()) ...
    【解决方案2】:

    我想告诉你@flo 的答案是正确的。但在这里我会给出另一种选择,我相信这不是你的代码直截了当的,但也许它会引起你的兴趣。

    @flo 回答,非常适合您的问题,但是您以连接代码业务逻辑访问和角色的方式描述了角色使用,这可以毫不费力地改进。

    因此,您可以以更灵活的方式进行操作,使用在向 DB 中添加新角色时不需要更改的类。

    我的意思是:

    public class Role {
        private Integer roleId = null;
        private String roleName = null;
    
        private static Map<Integer, String> roleMap = null;
        ...
    }
    

    您可以在应用程序的开头填充roleMap,当它正在加载时,从数据库或使用一些属性文件甚至使用Spring Beans(*在最后两种情况下,您需要修改此文件以添加新角色或更改其名称)以将具有该角色的 ID 分配到数据库中。

    但最大的问题是,我如何以这种方式检查用户授权?

    这可能对您的代码有点破坏性,但值得花点时间考虑一下。至少,有两种选择:

    使用动作

    显然,如果您不想获得对角色名称或角色 ID 的编译依赖项,我会建议您使用操作。操作可以是另一个连接表,用于将一组操作(字符串)与角色匹配。

    Role 类添加第二个静态映射

    private Map<String, Set<String>> roleActionMap = null;
    

    将允许您实现以下方法

    public boolean isAuthorized(String action, String role){
        boolean result = false;
    
        Set<String> actions = getActionSet(role);
        if(actions != null)
            result = actions.contains(action);
    
        return result;
    }
    

    您必须在业务逻辑方法中连接操作以请求授权。重新排序代码后,它会变得更加清晰,并且即使不更改代码也可以更灵活地重新调整角色行为。

    映射方法和角色

    以非常相似的方式,您可以将角色与方法名称关联起来,而不是创建映射来关联角色和操作,这样您就可以使用反射来检查方法是否被授权给角色。

    所以你可以检查用户授权调用相同的上述方法,而不是传递动作名称,传递

    Thread.currentThread().getStackTrace()[1].getMethodName();
    

    这将为您提供要检查授权的运行方法的名称。 (还有其他方法可以使用反射来获取方法名,这可能更合适,具体取决于场景

    最后,还有更复杂更好的框架,SpringSecurity 是一头野兽,但如果你想对业务逻辑进行授权,并且你不关心在视图逻辑和 UI 上使用授权,我认为我的两个替代方案不错。

    希望对你有帮助。

    【讨论】:

    • 不错的解决方案(但对我来说太过分了)!
    猜你喜欢
    • 2011-08-12
    • 1970-01-01
    • 2022-01-03
    • 2017-07-01
    • 1970-01-01
    • 2023-03-25
    • 1970-01-01
    • 2021-10-04
    • 1970-01-01
    相关资源
    最近更新 更多