Dur*_*rin 6 java spring acl spring-security java-ee
我使用Spring Security 3.1 ACL实现.所以根据一个教程,我创建了一个带有下表的acl数据库:
CREATE TABLE IF NOT EXISTS `acl_class` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`class` varchar(255) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `unique_uk_2` (`class`)
) ENGINE=InnoDB;
CREATE TABLE IF NOT EXISTS `acl_entry` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`acl_object_identity` bigint(20) NOT NULL,
`ace_order` int(11) NOT NULL,
`sid` bigint(20) NOT NULL,
`mask` int(11) NOT NULL,
`granting` tinyint(1) NOT NULL,
`audit_success` tinyint(1) NOT NULL,
`audit_failure` tinyint(1) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `unique_uk_4` (`acl_object_identity`,`ace_order`),
KEY `foreign_fk_5` (`sid`)
) ENGINE=InnoDB;
CREATE TABLE IF NOT EXISTS `acl_object_identity` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`object_id_class` bigint(20) NOT NULL,
`object_id_identity` bigint(20) NOT NULL,
`parent_object` bigint(20) DEFAULT NULL,
`owner_sid` bigint(20) DEFAULT NULL,
`entries_inheriting` tinyint(1) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `unique_uk_3` (`object_id_class`,`object_id_identity`),
KEY `foreign_fk_1` (`parent_object`),
KEY `foreign_fk_3` (`owner_sid`)
) ENGINE=InnoDB;
CREATE TABLE IF NOT EXISTS `acl_sid` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`principal` tinyint(1) NOT NULL,
`sid` varchar(100) NOT NULL,
`password` varchar(255) NOT NULL,
`salt` varchar(255) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB;
Run Code Online (Sandbox Code Playgroud)
这适用于Anntotations,如:
@PreAuthorize("hasPermission(#element, 'WRITE')")
@PostAuthorize("hasPermission(returnObject, 'READ')")
Run Code Online (Sandbox Code Playgroud)
权限"读取"和"写入"在表acl_entry中设置为字段掩码.我理解1表示"READ",2表示"写入",4表示"创建",8表示"删除",16表示"管理",因为它似乎是一种按位认证方法.
现在我必须为"READ"和"Write"权限创建单个条目,这不是很方便.
根据PacktPub的Spring Security 3.1:
不幸的是,实际实现AclImpl直接比较了我们的[@PostFilter]注释中的SpEL表达式中指定的权限,以及数据库中存储在ACE上的权限,而不使用按位逻辑.Spring Security社区正在争论这是无意的还是按预期工作...
该书中的示例试图完全按照您所描述的内容进行操作 - 它指定角色为3的用户进行读/写,但拒绝用户访问权限掩码为1的对象进行读取.
解决方案是编写自己的自定义权限评估程序.
MyPermissionEvaluator.java:
public class MyPermissionEvaluator implements PermissionEvaluator {
@Override
public boolean hasPermission(Authentication authentication, Object targetDomainObject, Object requiredPermissions) {
//some way to access your user's assigned permission mask
int permissionMask = MyUserDetails.getMask();
//the requiredPermissions object must be cast as a String, and then
//converted to an integer, even though it is an integer in the ACL table
int permissionsRequired = Integer.valueOf(requiredPermissions.toString());
//a simple bitwise OR will identify whether the user has the required permissions
return ((permissionMask | permissionsRequired) == permissionMask);
}
. . .
}
Run Code Online (Sandbox Code Playgroud)
要实际使用此自定义权限评估程序,请编辑您的security.xml文件:
<security:global-method-security pre-post-annotations="enabled">
<security:expression-handler ref="expressionHandler"/>
</security:global-method-security>
<bean id="espressionHandler" class="org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler">
<property name="permissionEvaluator" ref="permissionEvaluator"/>
</bean>
<bean id="permissionEvaluator" class="my.project.package.MyPermissionEvaluator"/>
Run Code Online (Sandbox Code Playgroud)
最后,只要方法或类需要特定的权限级别:
@PreAuthorize("hasPermission(#this, '4')")
public void mySecuredMethod() { //some secured method
}
Run Code Online (Sandbox Code Playgroud)
现在,您可以将ACL表中的权限掩码设置为与组织需求相对应的任何内容(按位),并以您识别每个用户的权限的方式执行相同操作.例如,
user site_admin_bit database_admin_bit edit_data_bit write_data_bit read_data_bit
nancy 0 1 1 0 1
Run Code Online (Sandbox Code Playgroud)
Nancy因此存储在用户详细信息实现中的权限掩码为13(可能为31).如果她尝试访问具有权限要求的对象,edit_data则将根据掩码要求4检查其权限,并且按位OR评估(permissionMask | permissionsRequired == permissionMask)将评估为true.
根据我的估计,这是实现组织特定的按位权限掩码的最简单方法(使用32位进行操作,这应该足够了,我应该这么认为).根据引用的书,hasPermissionSpring注释中使用的SpEL表达式将用户的权限评估为一个完整的单元; 如果用户将权限设置为3以进行读/写,但注释仅针对read(1)进行评估,则将拒绝用户访问.
正如上一段所述,ACL 系统使用整数位掩码。不用担心,您无需了解使用 ACL 系统的位移位的细节,但足以说明我们有 32 位可以打开或关闭。这些位中的每一位都代表一个权限,默认情况下,权限为读取(位 0)、写入(位 1)、创建(位 2)、删除(位 3)和管理(位 4)。如果您希望使用其他权限,则可以轻松实现您自己的 Permission 实例,并且 ACL 框架的其余部分将在不了解您的扩展的情况下运行。
@question#1:是的,没错。
@question#2:您可以使用类似以下内容:
new BasePermission(BasePermission.WRITE.getMask() | BasePermission.READ.getMask())
来获得READ和WRITE许可。
来自春季文档:
// Prepare the information we'd like in our access control entry (ACE)
ObjectIdentity oi = new ObjectIdentityImpl(Foo.class, new Long(44));
Sid sid = new PrincipalSid("Samantha");
//Permission p = BasePermission.ADMINISTRATION;
Permission p = new BasePermission(BasePermission.WRITE.getMask() | BasePermission.READ.getMask());
// Create or update the relevant ACL
MutableAcl acl = null;
try {
acl = (MutableAcl) aclService.readAclById(oi);
} catch (NotFoundException nfe) {
acl = aclService.createAcl(oi);
}
// Now grant some permissions via an access control entry (ACE)
acl.insertAce(acl.getEntries().length, p, sid, true);
aclService.updateAcl(acl);
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
4683 次 |
| 最近记录: |