简体   繁体   English

如何实施Custom Spring Security ACL?

[英]How to implement Custom spring security acl?

I'm developing an Application using Spring. 我正在使用Spring开发应用程序。 In Access Control Access section I want to use Spring Security Acl (I'm new at Acl). 在“访问控制访问”部分,我想使用Spring Security Acl(我是Acl的新手)。 I want to implement ACL in my application base on 2 points: 我想基于两点在我的应用程序中实现ACL:

  1. Application should has five permissions, read , create , modify , delete and Administrator . 应用程序应具有五个权限,即readcreatemodifydeleteAdministrator
  2. Permissions be hierarchy, When a user has create permission, it should be able to read , Or when it has modify permission, it should be able to read , create and modify and etc. 权限是分层的,当用户拥有create权限时,它应该能够read ,或者当拥有modify权限时,它应该能够readcreatemodify等。

Is it possible? 可能吗? How? 怎么样?

update : 更新
My application is base on Spring MVC RESTFUL. 我的应用程序基于Spring MVC RESTFUL。 When a user wants to modify own information, he send some json data with Ajax. 当用户想要修改自己的信息时,他使用Ajax发送一些json数据。 An example of json data is as follow: json数据的示例如下:

{
  "id": 1,//user Id
  "name": "my name",
  "password": "my password",
  "email": "email@email.com",
   ...
}

Now, a malicious user can login to own account. 现在,恶意用户可以登录自己的帐户。 This user can modify its data like all other users. 该用户可以像其他所有用户一样modify其数据。 Before he send data, change his id, and modify another account user information. 在他发送数据之前,请更改其ID,然后modify另一个帐户用户信息。 I want to use ACL to prevent this Subversive work. 我想使用ACL来防止这种颠覆性工作。 And user can get some access to other that others can modify his info. 用户可以访问其他用户,其他人可以修改其信息。

You can implement a simple solution with spring security. 您可以使用spring安全性实现一个简单的解决方案。 The idea is to create a class that implements org.springframework.security.access.PermissionEvaluator and override the method hasPermission . 这个想法是创建一个实现org.springframework.security.access.PermissionEvaluator的类,并重写hasPermission方法。 Look the next example: 看下一个例子:

@Component("permissionEvaluator")
public class PermissionEvaluator implements org.springframework.security.access.PermissionEvaluator {

    /**
     * @param authentication     represents the user in question. Should not be null.
     * @param targetDomainObject the domain object for which permissions should be
     *                           checked. May be null in which case implementations should return false, as the null
     *                           condition can be checked explicitly in the expression.
     * @param permission         a representation of the permission object as supplied by the
     *                           expression system. Not null.
     * @return true if the permission is granted, false otherwise
     */
    @Override
    public boolean hasPermission(Authentication authentication, Object targetDomainObject, Object permission) {
        if (authentication != null && permission instanceof String) {
            User loggedUser = (User) authentication.getPrincipal();
            String permissionToCheck = (String) permission;
            // in this part of the code you need to check if the loggedUser has the "permission" over the
            // targetDomainObject. In this implementation the "permission" is a string, for example "read", or "update"
            // The targetDomainObject is an actual object, for example a object of UserProfile class (a class that
            // has the profile information for a User)

            // You can implement the permission to check over the targetDomainObject in the way that suits you best
            // A naive approach:
            if (targetDomainObject.getClass().getSimpleName().compareTo("UserProfile") == 0) {
                if ((UserProfile) targetDomainObject.getId() == loggedUser.getId())
                    return true;
            }
            // A more robust approach: you can have a table in your database holding permissions to each user over
            // certain targetDomainObjects
            List<Permission> userPermissions = permissionRepository.findByUserAndObject(loggedUser,
                targetDomainObject.getClass().getSimpleName());
            // now check if in userPermissions list we have the "permission" permission.

            // ETC...
        }
        //access denied
        return false;
    }

}

Now, with this implementation you can use in for example your service layer the @PreAuthorize annotation like this: 现在,通过此实现,您可以在服务层中使用@PreAuthorize注释,如下所示:

@PreAuthorize("hasPermission(#profile, 'update')")
public void updateUserProfileInASecureWay(UserProfile profile) {
    //code to update user profile
}

The "hasPermission" inside the @PreAuthorize annotation receives the targetDomainObject #profile from the params of the updateUserProfileInASecureWay method and also we pass the required permission (in this case 'update'). @PreAuthorize批注中的“ hasPermission”从updateUserProfileInASecureWay方法的参数中接收targetDomainObject #profile,并且我们还传递了所需的权限(在本例中为“ update”)。

This solution avoids all the complexity of the ACL by implementing a "small" ACL. 该解决方案通过实现“小型” ACL避免了ACL的所有复杂性。 Maybe it can work for you. 也许它可以为您工作。

You can use the role hierarchy combination as used in the following examples.Spring acl has base permissions,If you want to implement Custom permissions you need to create a custom Permission class extending Base Permissions class in the api. 您可以使用以下示例中使用的角色层次结构组合。Spring acl具有基本权限,如果要实现自定义权限,则需要创建一个自定义Permission类,以扩展api中的Base Permissions类。 we can define roles for each kind of permission and define role hierarchy as below. 我们可以为每种权限定义角色,并如下定义角色层次结构。

<bean id="expressionHandler"
    class="org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler">
    <property name="permissionEvaluator" ref="permissionEvaluator" />
    <property name="roleHierarchy" ref="roleHierarchy" />
</bean>

<!-- A customized PermissionEvaluator that evaluates permissions via the ACL module -->
<bean class="org.springframework.security.acls.AclPermissionEvaluator" id="permissionEvaluator">
    <!-- Reference to the ACL service which performs JDBC calls to an ACL database -->
    <constructor-arg ref="aclService"/>
     <property name="permissionFactory" ref="customPermissionFactory" /> 
</bean>
<bean id="customPermissionFactory" class="org.krams.tutorial.security.CustomPermissionFactory"></bean>

<!-- A customized ACL service which provides default JDBC implementation -->
<bean class="org.springframework.security.acls.jdbc.JdbcMutableAclService" id="aclService">
    <constructor-arg ref="dataSource"/>
    <constructor-arg ref="lookupStrategy"/>
    <constructor-arg ref="aclCache"/>
</bean>

<!-- A lookup strategy for optimizing database queries -->
<bean id="lookupStrategy" class="org.springframework.security.acls.jdbc.BasicLookupStrategy">
    <constructor-arg ref="dataSource"/>
    <constructor-arg ref="aclCache"/>
    <constructor-arg ref="aclAuthorizationStrategy"/>
    <constructor-arg ref="auditLogger"/>
    <property name="permissionFactory" ref="customPermissionFactory"/>
</bean>

<!-- A MySQL datasource with pooling capabalities for the ACL module -->
<!-- <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"
     destroy-method="close"
     p:driverClass="com.mysql.jdbc.Driver"
     p:jdbcUrl="jdbc:mysql://localhost/acl"
     p:user="root"
     p:password=""
     p:acquireIncrement="5"
     p:idleConnectionTestPeriod="60"
     p:maxPoolSize="100"
     p:maxStatements="50"
     p:minPoolSize="10" /> -->




<bean id="dataSource"
    class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    <property name="driverClassName" value="org.h2.Driver" />
    <property name="url" value="jdbc:h2:tcp://localhost/~/springsecurity" />

    <!--<property name="url" value="jdbc:h2:tcp://ggk-wrl-win1/~/dev" /> -->
    <property name="username" value="sa" />
    <property name="password" value="" />
</bean>

<!-- An ACL cache to minimize calls to the ACL database -->   
<bean id="aclCache" class="org.springframework.security.acls.domain.EhCacheBasedAclCache">
    <constructor-arg>
        <bean class="org.springframework.cache.ehcache.EhCacheFactoryBean">
            <property name="cacheManager">
                <bean class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"/>
            </property>
            <property name="cacheName" value="aclCache"/>
        </bean>
    </constructor-arg>
</bean>

<!-- An ACL authorization strategy to determine whether a principal is permitted to call administrative methods -->
<bean id="aclAuthorizationStrategy" class="org.springframework.security.acls.domain.AclAuthorizationStrategyImpl">
    <constructor-arg>
        <list>
            <bean class="org.springframework.security.core.authority.GrantedAuthorityImpl">
                <constructor-arg value="ROLE_USER"/>
            </bean>
            <bean class="org.springframework.security.core.authority.GrantedAuthorityImpl">
                <constructor-arg value="ROLE_USER"/>
            </bean>
            <bean class="org.springframework.security.core.authority.GrantedAuthorityImpl">
                <constructor-arg value="ROLE_USER"/>
            </bean>
        </list>
    </constructor-arg>
</bean>

<!-- An audit logger used to log audit events -->
<bean id="auditLogger" class="org.springframework.security.acls.domain.ConsoleAuditLogger"/>

<!-- Defines the role order -->
<!-- http://static.springsource.org/spring-security/site/docs/3.0.x/apidocs/org/springframework/security/access/hierarchicalroles/RoleHierarchyImpl.html -->
<bean id="roleHierarchy"  class="org.springframework.security.access.hierarchicalroles.RoleHierarchyImpl">
    <property name="hierarchy">
        <value>
            ROLE_ADMIN > ROLE_USER
            ROLE_USER > ROLE_VISITOR
        </value>
    </property>
</bean>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM