`
joerong666
  • 浏览: 418305 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论

集成ACEGI 进行权限控制

阅读更多

集成ACEGI 进行权限控制

转自:http://acegi-test.sourceforge.net/

一. 简单介绍

1.1 本文目的

集成Acegi到自己的项目中, 并且将用户信息和权限放到数据库, 提供方法允许权限动态变化,变化后自动加载最新的权限

本文介绍Acegi例子的时候采用的是acegi-security-samples-tutorial-1.0.6.war

阅读本文需要对Spring有一定的了解, 如果你还没有接触过, 有些地方可能不容易理解, 这时候可能需要参考本文后附的Spring地址, 先了解一下Spring的基本知识.

本文使用的是Mysql数据库, 如果你使用其他的数据库, 可能需要修改相应的SQL.

1.2 安装与配置

项目主页: http://www.acegisecurity.org/

下载地址: http://sourceforge.net/project/showfiles.php?group_id=104215

解压文件后, 将acegi-security-samples-tutorial-1.0.6.war复制Your_Tomcat_Path/webapps/

启动Tomcat, 访问http://localhost:8080/acegi-security-samples-tutorial-1.0.6/

点击页面上任何一个链接,都需要用户登录后访问, 可以在页面上看到可用的用户名和密码.

二. 开始集成到自己的程序中

2.1 将用户和角色放在数据库中

可能是为了演示方便, 简单的展示Acegi如何控制权限, 而不依赖于任何数据库, ACEGI给出的例子采用InMemoryDaoImpl获取用户信息, 用户和角色信息放在WEB-INF/users.properties 文件中, InMemoryDaoImpl 一次性的从该配置文件中读出用户和角色信息, 格式是: 用户名=密码, 角色名, 如第一行是:

marissa=koala,ROLE_SUPERVISOR

就是说marissa的密码是koala, 并且他的角色是ROLE_SUPERVISOR

对这个文件的解析是通过applicationContext-acegi-security.xml中如下的设置进行的:

<!-- UserDetailsService is the most commonly frequently Acegi Security interface implemented by end users -->

<bean id="userDetailsService"
    class="org.acegisecurity.userdetails.memory.InMemoryDaoImpl">
    <property name="userProperties">
        <bean
            class="org.springframework.beans.factory.config.PropertiesFactoryBean">
            <property name="location"
                value="classpath:users.properties" />
        </bean>
    </property>
</bean>

 

除了InMemoryDaoImpl之外, ACEGI还提供了Jdbc和 ldap的支持, 由于使用数据库进行验证比较常见, 下面仅就jdbc实现做出介绍.

不管是InMemoryDaoImpl还是JdbcDaoImpl都是实现了UserDetailsService接口, 而这个接口里只定义了一个方法: UserDetails loadUserByUsername(String username) 就是根据用户名加载UserDetails对象, UserDetails也是一个接口, 定义了一个用户所需要的基本信息, 包括: username, password, authorities等信息

2.1.1 直接使用JdbcDaoImpl 访问数据库中的用户信息

如果ACEGI提供的信息满足你的需要, 也就是说你只需要用户的username, password等信息, 你可以直接使用ACEGI提供的Schema, 这样, 不需要任何变动, JdbcDaoImpl就可以使用了.

如果你的数据库已经定义好了, 或者不想使用ACEGI提供的Schema,那么你也可以自定义JdbcDaoImpl的查询语句

        <property name="usersByUsernameQuery">
            <value>
                SELECT email, password, enabled from user u where email = ? 
            </value>
        </property>

        <property name="authoritiesByUsernameQuery">
            <value>
                SELECT u.email, r.role_name FROM user_role ur, user u, role r WHERE 
                    ur.user_id = u.user_id and ur.role_id = r.role_id and u.email = ? 
            </value>
        </property>

2.1.2 扩展JdbcDaoImpl获取更多用户信息

如果上面提到的定制查询SQL语句不能提供足够的灵活性, 那么你可能就需要定义一个JdbcDaoImpl的子类, 如果变动不大, 通过覆盖initMappingSqlQueries方法重新定义MappingSqlQuery的实例. 而如果你需要获取更多信息, 比如userId, companyId等, 那就需要做更多的改动, 第一种改动不大, 所以不具体介绍, 下面以第二种改动为例,介绍如何实现这种需求.

我们需要三张表User, Role, User_Role, 具体的SQL如下:

#
# Structure for the `role` table : 
#

DROP TABLE IF EXISTS `role`;

CREATE TABLE `role` (
  `role_id` int(11) NOT NULL auto_increment,
  `role_name` varchar(50) default NULL,
  `description` varchar(20) default NULL,
  `enabled` tinyint(1) NOT NULL default '1',
  PRIMARY KEY  (`role_id`)
);

#
# Structure for the `user` table : 
#

DROP TABLE IF EXISTS `user`;

CREATE TABLE `user` (
  `user_id` int(11) NOT NULL auto_increment,
  `company_id` int(11) default NULL,
  `email` varchar(200) default NULL,
  `password` varchar(10) default NULL,
  `enabled` tinyint(1) default NULL,
  PRIMARY KEY  (`user_id`)
);

#
# Structure for the `user_role` table : 
#

DROP TABLE IF EXISTS `user_role`;

CREATE TABLE `user_role` (
  `user_role_id` int(11) NOT NULL auto_increment,
  `user_id` varchar(50) NOT NULL,
  `role_id` int(11) NOT NULL,
  PRIMARY KEY  (`user_role_id`)
);

前面讲过, UserDetailsService接口中只定义了一个方法: UserDetails loadUserByUsername(String username), UserDetails中不存在我们需要的userId 和companyId等信息, 所以我们首先需要扩展UserDetails接口, 并扩展org.acegisecurity.userdetails.User:

IUserDetails.java

package org.security;

import org.acegisecurity.GrantedAuthority;

/**
 * The class <code>IUserDetails</code> extends the org.acegisecurity.userdetails.UserDetails interface, and provides additional userId, companyId information<br><br>
 * @author wade
 * @see UserDetails
 */
public interface IUserDetails extends org.acegisecurity.userdetails.UserDetails{

    public int getUserId();

    public void setUserId(int user_id);

    public int getCompanyId();

    public void setCompanyId(int company_id);
    
    public String getUsername();

    public void setUsername(String username);

    public GrantedAuthority[] getAuthorities();

    public void setAuthorities(GrantedAuthority[] authorities);
}

 

UserDetailsImpl.java

package org.security;

import org.acegisecurity.GrantedAuthority;
import org.acegisecurity.userdetails.User;

/**
 * The class <code>UserDetailsImpl</code> extends the org.acegisecurity.userdetails.User class, and provides additional userId, companyId information
 * @author wade
 * 
 * @see IUserDetails, User
 */
public class UserDetailsImpl extends User implements IUserDetails{
    private int user_id;
    private int company_id;
    private String username;
    private GrantedAuthority[] authorities;
    
    public UserDetailsImpl(String username, String password, boolean enabled,
            boolean accountNonExpired, boolean credentialsNonExpired,
            boolean accountNonLocked, GrantedAuthority[] authorities)
            throws IllegalArgumentException {
        super(username, password, enabled, accountNonExpired, credentialsNonExpired,
                accountNonLocked, authorities);
        setUsername(username);
        setAuthorities(authorities);        
    }
    
    public UserDetailsImpl(int userid, int companyid, String username, String password, boolean enabled,
            boolean accountNonExpired, boolean credentialsNonExpired,
            boolean accountNonLocked, GrantedAuthority[] authorities)
            throws IllegalArgumentException {
        super(username, password, enabled, accountNonExpired, credentialsNonExpired,
                accountNonLocked, authorities);
        this.user_id = userid;
        this.company_id = companyid;
        setUsername(username);
        setAuthorities(authorities);    
    }

    public int getUserId() {
        return user_id;
    }

    public void setUserId(int user_id) {
        this.user_id = user_id;
    }

    public int getCompanyId() {
        return company_id;
    }

    public void setCompanyId(int company_id) {
        this.company_id = company_id;
    }
    
    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public GrantedAuthority[] getAuthorities() {
        return authorities;
    }

    public void setAuthorities(GrantedAuthority[] authorities) {
        this.authorities = authorities;
    }
}

 

到此为止, 我们已经准备好了存放用户信息的类, 下面就开始动手修改取用户数据的代码.

假设我们用下面的SQL取用户信息:

SELECT u.user_id, u.company_id, email, password, enabled 
    FROM role r, user_role ur, user u 
    WHERE r.role_id = ur.role_id 
        and ur.user_id = u.user_id 
        and email = ? 
    limit 1 

用下面的SQL取用户具有的Role列表

SELECT u.email, r.role_name 
    FROM user_role ur, user u, role r 
    WHERE ur.user_id = u.user_id 
        and ur.role_id = r.role_id 
        and u.email = ? 

 

我们需要修改的主要是两部分:

1. 取用户和用户角色的MappingSqlQuery, 增加了查询的userId和companyId.

2. loadUserByUsername方法, 修改了返回的对象类型,和很少的内部代码.

AcegiJdbcDaoImpl.java

package org.security.acegi;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import java.util.List;

import javax.sql.DataSource;

import org.acegisecurity.GrantedAuthority;
import org.acegisecurity.GrantedAuthorityImpl;
import org.acegisecurity.userdetails.UsernameNotFoundException;
import org.acegisecurity.userdetails.jdbc.JdbcDaoImpl;

import org.security.IUserDetails;
import org.security.UserDetailsImpl;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.SqlParameter;
import org.springframework.jdbc.object.MappingSqlQuery;

/**
 * The class AcegiJdbcDaoImpl provides the method to get IUserDetail information from db which contains userId, companyId and UserDetail information.
 * 
 * @author wade
 *
 */
public class AcegiJdbcDaoImpl extends JdbcDaoImpl {
     public static final String DEF_USERS_BY_USERNAME_QUERY =
         "SELECT u.user_id, u.company_id, email, password, enabled from role r, user_role ur, user u where r.role_id = ur.role_id and ur.user_id = u.user_id and email = ? limit 1";
     public static final String DEF_AUTHORITIES_BY_USERNAME_QUERY =
         "SELECT username,authority FROM authorities WHERE username = ?";

    protected MappingSqlQuery rolesByUsernameMapping;
    protected MappingSqlQuery usersByNameMapping;
        
    private String authoritiesByUsernameQuery;
    private String rolePrefix = "";
    private String usersByUsernameQuery;
    private boolean usernameBasedPrimaryKey = true;
    
    public AcegiJdbcDaoImpl(){
        usersByUsernameQuery = DEF_USERS_BY_USERNAME_QUERY;
        authoritiesByUsernameQuery = DEF_AUTHORITIES_BY_USERNAME_QUERY;
    }
    public String getAuthoritiesByUsernameQuery() {
        return authoritiesByUsernameQuery;
    }

    public String getRolePrefix() {
        return rolePrefix;
    }

    public String getUsersByUsernameQuery() {
        return usersByUsernameQuery;
    }

    protected void initMappingSqlQueries() {
        this.usersByNameMapping = new UsersByUsernameMapping(getDataSource());
        this.rolesByUsernameMapping = new AuthoritiesByUsernameMapping(getDataSource());
    }

    /**
     * Allows the default query string used to retrieve authorities based on username to be overriden, if
     * default table or column names need to be changed. The default query is {@link
     * #DEF_AUTHORITIES_BY_USERNAME_QUERY}; when modifying this query, ensure that all returned columns are mapped
     * back to the same column names as in the default query.
     *
     * @param queryString The query string to set
     */
    public void setAuthoritiesByUsernameQuery(String queryString) {
        authoritiesByUsernameQuery = queryString;
    }

    /**
     * Allows a default role prefix to be specified. If this is set to a non-empty value, then it is
     * automatically prepended to any roles read in from the db. This may for example be used to add the
     * <code>ROLE_</code> prefix expected to exist in role names (by default) by some other Acegi Security framework
     * classes, in the case that the prefix is not already present in the db.
     *
     * @param rolePrefix the new prefix
     */
    public void setRolePrefix(String rolePrefix) {
        this.rolePrefix = rolePrefix;
    }

    /**
     * If <code>true</code> (the default), indicates the {@link #getUsersByUsernameQuery()} returns a username
     * in response to a query. If <code>false</code>, indicates that a primary key is used instead. If set to
     * <code>true</code>, the class will use the database-derived username in the returned <code>UserDetailsImpl</code>.
     * If <code>false</code>, the class will use the {@link #loadUserByUsername(String)} derived username in the
     * returned <code>UserDetailsImpl</code>.
     *
     * @param usernameBasedPrimaryKey <code>true</code> if the mapping queries return the username <code>String</code>,
     *        or <code>false</code> if the mapping returns a database primary key.
     */
    public void setUsernameBasedPrimaryKey(boolean usernameBasedPrimaryKey) {
        this.usernameBasedPrimaryKey = usernameBasedPrimaryKey;
    }

    /**
     * Allows the default query string used to retrieve users based on username to be overriden, if default
     * table or column names need to be changed. The default query is {@link #DEF_USERS_BY_USERNAME_QUERY}; when
     * modifying this query, ensure that all returned columns are mapped back to the same column names as in the
     * default query. If the 'enabled' column does not exist in the source db, a permanent true value for this column
     * may be returned by using a query similar to <br><pre>
     * "SELECT username,password,'true' as enabled FROM users WHERE username = ?"</pre>
     *
     * @param usersByUsernameQueryString The query string to set
     */
    public void setUsersByUsernameQuery(String usersByUsernameQueryString) {
        this.usersByUsernameQuery = usersByUsernameQueryString;
    }
    
    public IUserDetails loadUserByUsername(String username)
        throws UsernameNotFoundException, DataAccessException {
        List users = usersByNameMapping.execute(username);

        if (users.size() == 0) {
            throw new UsernameNotFoundException("User not found");
        }

        IUserDetails user = (IUserDetails) users.get(0); // contains no GrantedAuthority[]

        List dbAuths = rolesByUsernameMapping.execute(user.getUsername());

        addCustomAuthorities(user.getUsername(), dbAuths);

        if (dbAuths.size() == 0) {
            throw new UsernameNotFoundException("User has no GrantedAuthority");
        }

        GrantedAuthority[] arrayAuths = (GrantedAuthority[]) dbAuths.toArray(new GrantedAuthority[dbAuths.size()]);

        user.setAuthorities(arrayAuths);

        if (!usernameBasedPrimaryKey) {
            user.setUsername(username);
        }

        return user;
    }
    
    /**
     * Query object to look up a user's authorities.
     */
    protected class AuthoritiesByUsernameMapping extends MappingSqlQuery {
        protected AuthoritiesByUsernameMapping(DataSource ds) {
            super(ds, authoritiesByUsernameQuery);
            declareParameter(new SqlParameter(Types.VARCHAR));
            compile();
        }

        protected Object mapRow(ResultSet rs, int rownum)
            throws SQLException {
            String roleName = rolePrefix + rs.getString(2);
            GrantedAuthorityImpl authority = new GrantedAuthorityImpl(roleName);

            return authority;
        }
    }

    /**
     * Query object to look up a user.
     */
    protected class UsersByUsernameMapping extends MappingSqlQuery {
        protected UsersByUsernameMapping(DataSource ds) {
            super(ds, usersByUsernameQuery);
            declareParameter(new SqlParameter(Types.VARCHAR));
            compile();
        }

        protected Object mapRow(ResultSet rs, int rownum)
            throws SQLException {
            int user_id = rs.getInt(1);
            int company_id = rs.getInt(2);
            String username = rs.getString(3);
            String password = rs.getString(4);
            boolean enabled = rs.getBoolean(5);
            
            IUserDetails user = new UserDetailsImpl(username, password, enabled, true, true, true,
                    new GrantedAuthority[] {new GrantedAuthorityImpl("HOLDER")});
            user.setUserId(user_id);
            user.setCompanyId(company_id);
            return user;
        }
    }
}

 

修改spring配置, 使用我们新建立的类:

    <bean id="userDetailsService"
        class="org.security.acegi.AcegiJdbcDaoImpl">
        <property name="dataSource">
            <ref bean="dataSource" />
        </property>

        <property name="usersByUsernameQuery">
            <value>
                SELECT u.user_id, u.company_id, email, password, enabled
                    from role r, user_role ur, user u where r.role_id = ur.role_id and ur.user_id = u.user_id 
                    and email = ?
                    limit 1
            </value>
        </property>

        <property name="authoritiesByUsernameQuery">
            <value>
                SELECT u.email, r.role_name FROM user_role ur, user u, role r WHERE
                ur.user_id = u.user_id and ur.role_id = r.role_id and u.email = ?
            </value>
        </property>
    </bean>

 

好了, 如果再有用户登录,就会调用我们的loadUserByUsername, 从数据库中读取用户数据了, 那用户的权限都有什么呢? 一个用户又对应着哪些ROLE呢? 下面先讲一下ACEGI 例子中的权限设置

2.2 将权限放在数据库中

截止到1.0.6版, Acegi没有提供直接从数据库读取权限的方法, 而是采用通过如下的配置设置权限:

    <bean id="filterInvocationInterceptor"
        class="org.acegisecurity.intercept.web.FilterSecurityInterceptor">
        <property name="authenticationManager" ref="authenticationManager" />
        <property name="accessDecisionManager">
            <bean class="org.acegisecurity.vote.AffirmativeBased">
                <property name="allowIfAllAbstainDecisions" value="false" />
                <property name="decisionVoters">
                    <list>
                        <bean class="org.acegisecurity.vote.RoleVoter" />
                        <bean class="org.acegisecurity.vote.AuthenticatedVoter" />
                    </list>
                </property>
            </bean>
        </property>
        
        <property name="objectDefinitionSource">
            <value><![CDATA[
                CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
                PATTERN_TYPE_APACHE_ANT
                /secure/extreme/**=ROLE_SUPERVISOR
                /secure/**=IS_AUTHENTICATED_REMEMBERED
                /project/**=IS_AUTHENTICATED_REMEMBERED
                /task/**=ROLE_DEVELOPER                
                /**=IS_AUTHENTICATED_ANONYMOUSLY
            ]]></value>
        </property>
    </bean>

 

而对大部分项目, 将权限放在数据库中可能是更灵活的, 为此, 我们需要写一个类去读取权限, 为了使这个类尽量简单, 我们把它做成PathBasedFilterInvocationDefinitionMap和RegExpBasedFilterInvocationDefinitionMap的代理类, PathBasedFilterInvocationDefinitionMap 采用的是Ant Path 风格的匹配方式, 而RegExpBasedFilterInvocationDefinitionMap采用的是Perl5风格的匹配方式. 用户可以通过在配置文件中设置来选择具体比较方式, 默认的比较方式是Ant Path 风格的匹配方式.

这样我们需要做的就是读取权限列表, 并放到相应的代理类里面, 而具体的比较则由代理类进行.

需要的表结构: Resource, Role_Resource

DROP TABLE IF EXISTS `resource`;

CREATE TABLE `resource` (
  `resource_id` int(11) NOT NULL auto_increment,
  `parent_resource_id` int(11) default NULL,
  `resource_name` varchar(50) default NULL,
  `description` varchar(100) default NULL,
  PRIMARY KEY  (`resource_id`)
);

#
# Structure for the `resource_role` table : 
#

DROP TABLE IF EXISTS `resource_role`;

CREATE TABLE `resource_role` (
  `resource_role_id` int(11) NOT NULL auto_increment,
  `resource_id` int(11) NOT NULL,
  `role_id` int(11) NOT NULL,
  PRIMARY KEY  (`resource_role_id`)
);

 

添加我们的类:

AcegiJdbcDefinitionSourceImpl.java

package org.security.acegi;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.sql.DataSource;

import org.acegisecurity.ConfigAttributeDefinition;
import org.acegisecurity.SecurityConfig;
import org.acegisecurity.intercept.web.FilterInvocationDefinitionMap;
import org.acegisecurity.intercept.web.FilterInvocationDefinitionSource;
import org.acegisecurity.intercept.web.PathBasedFilterInvocationDefinitionMap;
import org.acegisecurity.intercept.web.RegExpBasedFilterInvocationDefinitionMap;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.security.IResourceRole;
import org.security.ResourceRoleImpl;
import org.security.event.IPermissionListener;
import org.security.event.PermissionEventPublisher;

import org.springframework.beans.factory.InitializingBean;
import org.springframework.jdbc.core.support.JdbcDaoSupport;
import org.springframework.jdbc.object.MappingSqlQuery;

/**
 * 
 * The class <code>AcegiJdbcDefinitionSourceImpl</code> is proxy to
 * PathBasedFilterInvocationDefinitionMap or RegExpBasedFilterInvocationDefinitionMap, This class get the permission
 * settings from the database, the default sql script is: SELECT resource, role
 * FROM role_permission, if it doesn't match your needs, changed it in bean
 * setting. <br>
 * 
 * <br>
 * $log$<br>
 * <br>
 * 
 * @author $Author: wade $
 * @see
 */
public class AcegiJdbcDefinitionSourceImpl extends JdbcDaoSupport implements
        InitializingBean, FilterInvocationDefinitionSource{
    private Log logger = LogFactory.getLog(this.getClass());

    public static final String DEF_PERMISSIONS_QUERY = "SELECT resource, role FROM role_permission";
    
    /** The Perl5 expression */
    String PERL5_KEY = "PATTERN_TYPE_PERL5";

    /** The ant path expression */
    String ANT_PATH_KEY = "PATTERN_TYPE_APACHE_ANT";

    /* Set default to Ant Path Expression*/
    private String resourceExpression = ANT_PATH_KEY;

    private boolean convertUrlToLowercaseBeforeComparison = false;

    private FilterInvocationDefinitionMap definitionSource = null;

    private String permissionsQuery;

    private String rolePrefix = "";

    public AcegiJdbcDefinitionSourceImpl() {
        permissionsQuery = DEF_PERMISSIONS_QUERY;
    }

    public String getAuthoritiesByUsernameQuery() {
        return permissionsQuery;
    }

    public String getRolePrefix() {
        return rolePrefix;
    }

    /**
     * Allows the default query string used to retrieve permissions to be
     * overriden, if default table or column names need to be changed. The
     * default query is {@link #DEF_PERMISSIONS_QUERY}; when modifying this
     * query, ensure that all returned columns are mapped back to the same
     * column names as in the default query.
     * 
     * @param queryString
     *            The query string to set
     */
    public void setPermissionsQuery(String queryString) {
        permissionsQuery = queryString;
    }

    /**
     * Allows a default role prefix to be specified. If this is set to a
     * non-empty value, then it is automatically prepended to any roles read in
     * from the db. This may for example be used to add the <code>ROLE_</code>
     * prefix expected to exist in role names (by default) by some other Acegi
     * Security framework classes, in the case that the prefix is not already
     * present in the db.
     * 
     * @param rolePrefix
     *            the new prefix
     */
    public void setRolePrefix(String rolePrefix) {
        this.rolePrefix = rolePrefix;
    }

    /**
     * Init the permission list from db
     * 
     */
    protected void initMap() {
        // return if we have got the latest permission list
        if (definitionSource != null) {
            return;
        }

        logger.debug("getting permissions from db");
         if (PERL5_KEY.equals(getResourceExpression())) {
             definitionSource = new RegExpBasedFilterInvocationDefinitionMap();
        } else if (ANT_PATH_KEY.equals(getResourceExpression())) {
            definitionSource = new PathBasedFilterInvocationDefinitionMap();
        } else {
            throw new IllegalArgumentException("wrong resourceExpression value");
        }

        definitionSource.setConvertUrlToLowercaseBeforeComparison(isConvertUrlToLowercaseBeforeComparison());

        MappingSqlQuery permissionsMapping = new PermissionsMapping(
                getDataSource());
        List<IResourceRole> resources = permissionsMapping.execute();

        Map<String, String> map = new HashMap<String, String>();
        for (int i = 0; i < resources.size(); i++) {
            ConfigAttributeDefinition defn = new ConfigAttributeDefinition();

            String resource = resources.get(i).getResource();
            if (map.containsKey(resource)) {
                continue;
            } else {
                map.put(resource, resource);
            }

            for (int j = i; j < resources.size(); j++) {
                IResourceRole resourceRole = resources.get(j);
                if (resource.equals(resourceRole.getResource())) {
                    defn.addConfigAttribute(new SecurityConfig(resourceRole
                            .getRole()));
                    // logger.debug("added role: " + resourceRole.getRole());
                }
            }

            definitionSource.addSecureUrl(resources.get(i).getResource(), defn);
            // logger.debug("added roles to :" +
            // resources.get(i).getResource());
        }
    }

    /**
     * Query object to look up a user's authorities.
     */
    protected class PermissionsMapping extends MappingSqlQuery {
        protected PermissionsMapping(DataSource ds) {
            super(ds, permissionsQuery);
            compile();
        }

        protected IResourceRole mapRow(ResultSet rs, int rownum)
                throws SQLException {
            String resource = rs.getString(1);
            String role = rolePrefix + rs.getString(2);
            IResourceRole resourceRole = new ResourceRoleImpl(resource, role);

            return resourceRole;
        }
    }

    public ConfigAttributeDefinition getAttributes(Object object)
            throws IllegalArgumentException {
        initMap();

        if (definitionSource instanceof RegExpBasedFilterInvocationDefinitionMap) {
            return ((RegExpBasedFilterInvocationDefinitionMap) definitionSource).getAttributes(object);
        }else if(definitionSource instanceof PathBasedFilterInvocationDefinitionMap) {
            return ((PathBasedFilterInvocationDefinitionMap) definitionSource).getAttributes(object);
        }
        
        throw new IllegalStateException("wrong type of " + definitionSource + ", it should be " + RegExpBasedFilterInvocationDefinitionMap.class
                    + " or " + PathBasedFilterInvocationDefinitionMap.class); 
    }

    public Iterator getConfigAttributeDefinitions() {
        initMap();
        if (definitionSource instanceof RegExpBasedFilterInvocationDefinitionMap) {
            return ((RegExpBasedFilterInvocationDefinitionMap) definitionSource).getConfigAttributeDefinitions();
        }else if(definitionSource instanceof PathBasedFilterInvocationDefinitionMap) {
            return ((PathBasedFilterInvocationDefinitionMap) definitionSource).getConfigAttributeDefinitions();
        }
        
        throw new IllegalStateException("wrong type of " + definitionSource + ", it should be " + RegExpBasedFilterInvocationDefinitionMap.class
                    + " or " + PathBasedFilterInvocationDefinitionMap.class); 
    }

    public boolean supports(Class clazz) {
        initMap();
        
        if (definitionSource instanceof RegExpBasedFilterInvocationDefinitionMap) {
            return ((RegExpBasedFilterInvocationDefinitionMap) definitionSource).supports(clazz);
        }else if(definitionSource instanceof PathBasedFilterInvocationDefinitionMap) {
            return ((PathBasedFilterInvocationDefinitionMap) definitionSource).supports(clazz);
        }
        
        throw new IllegalStateException("wrong type of " + definitionSource + ", it should be " + RegExpBasedFilterInvocationDefinitionMap.class
                + " or " + PathBasedFilterInvocationDefinitionMap.class); 
    }

    
    public String getResourceExpression() {
        return resourceExpression;
    }

    public void setResourceExpression(String resourceExpression) {
        this.resourceExpression = resourceExpression;
    }

    public boolean isConvertUrlToLowercaseBeforeComparison() {
        return convertUrlToLowercaseBeforeComparison;
    }

    public void setConvertUrlToLowercaseBeforeComparison(
            boolean convertUrlToLowercaseBeforeComparison) {
        this.convertUrlToLowercaseBeforeComparison = convertUrlToLowercaseBeforeComparison;
    }
    
}

 

修改spring配置, 使用我们新建立的类和对应的SQL:

    <bean id="filterInvocationInterceptor"
        class="org.acegisecurity.intercept.web.FilterSecurityInterceptor">
        <property name="authenticationManager"
            ref="authenticationManager" />
        <property name="accessDecisionManager">
            <bean class="org.acegisecurity.vote.AffirmativeBased">
                <property name="allowIfAllAbstainDecisions"
                    value="false" />
                <property name="decisionVoters">
                    <list>
                        <bean class="org.acegisecurity.vote.RoleVoter" />
                        <bean
                            class="org.acegisecurity.vote.AuthenticatedVoter" />
                    </list>
                </property>
            </bean>
        </property>
        
        <property name="objectDefinitionSource">
            <ref bean="rolePermissionService"/>
        </property>
    </bean>

    <bean id="rolePermissionService"
        class="org.security.acegi.AcegiJdbcDefinitionSourceImpl">
        <property name="dataSource">
            <ref bean="dataSource" />
        </property>
        <property name="permissionsQuery">
            <value>
                SELECT resource_name, role_name FROM resource_role rr, resource re, role ro
                WHERE rr.role_id = ro.role_id and rr.resource_id = re.resource_id
            </value>
        </property>
        <property name="convertUrlToLowercaseBeforeComparison" value="false"></property>
        <property name="resourceExpression" value="PATTERN_TYPE_APACHE_ANT"></property>
    </bean>

 

2.3 使用JUnit进行测试

AcegiPermissionTestCase.java

package org.security;

import java.io.IOException;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

import org.acegisecurity.AccessDeniedException;
import org.acegisecurity.Authentication;
import org.acegisecurity.ConfigAttributeDefinition;
import org.acegisecurity.GrantedAuthority;
import org.acegisecurity.GrantedAuthorityImpl;
import org.acegisecurity.intercept.web.FilterInvocation;
import org.acegisecurity.intercept.web.FilterInvocationDefinitionSource;
import org.acegisecurity.intercept.web.FilterSecurityInterceptor;
import org.acegisecurity.providers.UsernamePasswordAuthenticationToken;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;

import org.security.BaseSpringTestCase;
import org.security.IResourceRole;
import org.security.IUserDetails;
import org.security.ResourceRoleImpl;
import org.security.acegi.AcegiJdbcDaoImpl;

/**
 * 
 * The class <code>AcegiP
分享到:
评论

相关推荐

    集成ACEGI 进行权限控制.rar

    这个压缩包“集成ACEGI 进行权限控制.rar”包含了实现这一功能所需的组件和详细教程,让我们一起深入探讨ACEGI Security的原理和应用。 1. **ACEGI Security概述** ACEGI Security的核心目标是提供一套灵活、可...

    Spring Acegi权限控制

    Spring Acegi权限控制是Spring框架中用于实现Web应用安全的一种解决方案。Acegi Security(现已被Spring Security替代)是一个功能强大的安全框架,它主要解决了认证(Authentication)和授权(Authorization)这两...

    acegi 权限控制按钮

    Acegi是Spring框架早期的一个安全模块,用于提供高级的安全性和权限控制。在本文中,我们将深入探讨Acegi如何实现精细的权限控制,直至按钮或HTML元素级别,以及如何将其部署到Tomcat服务器。 首先,Acegi的核心是...

    使用acegi控制用户权限实例

    在本实例中,我们将深入探讨如何使用Acegi来控制用户的权限。Acegi Security已经被Spring Security替代,但其核心思想和机制仍然适用于现代的Spring Security。 首先,我们需要理解Acegi的基础概念。Acegi的核心是`...

    权限Acegi的使用

    1. **集成Acegi**:将Acegi库添加到项目的类路径中,并在Spring配置文件中声明Acegi的安全配置。 2. **配置安全上下文**:定义安全上下文,指定认证和授权的策略。这包括设置认证提供者、访问决策管理器以及安全...

    Acegi安全权限管理手册

    Acegi的安全模型允许精细的权限控制,可以基于角色、URL、方法甚至业务对象进行授权。它使用AOP(面向切面编程)来实现权限检查,可以在任何代码执行点进行安全拦截。 4. **会话管理(Session Management)**: ...

    acegi java权限验证框架ppt讲座和代码

    3. **权限控制**:掌握Acegi如何通过AOP(面向切面编程)实现方法级别的权限控制,以及如何定义安全元数据(如访问表达式)来控制对象和操作的访问。 4. **目录权限认证**:理解如何为Web应用的URL路径设置访问权限...

    Acegi解决权限问题

    Acegi Security是Spring框架早期的一个安全模块,它为Java企业级应用提供了强大的权限管理...通过学习和分析这些资源,开发者不仅可以了解Acegi的安全机制,还能学会如何在实际项目中实施权限控制,提升应用的安全性。

    batis+acegi实现的动态权限控制

    综上所述,"batis+acegi实现的动态权限控制"是一个涉及MyBatis和Acegi Security集成的项目,目的是构建一个能够根据用户角色和权限动态调整访问控制的系统。在实际操作中,需要对这两个组件有深入理解,并进行适当的...

    mypro.rar_Acegi Appfuse2 _acegi_java 数据库_java 权限_数据权限控制

    Acegi的强大之处在于它能够无缝集成到Spring环境中,使得开发者可以方便地实现复杂的权限控制策略。在本项目中,Acegi主要负责用户的登录验证、角色分配以及资源访问权限的控制。 Appfuse是一个开源项目,旨在简化...

    基于rbac模式的acegi权限管理

    总之,基于RBAC模式的Acegi权限管理是Spring框架下实现安全控制的一种强大工具。通过合理的设计和配置,我们可以构建出既安全又易于维护的权限管理系统。对于需要处理大量用户和复杂权限需求的企业级应用来说,这样...

    最简单acegi权限管理实例

    总的来说,这个"最简单acegi权限管理实例"是一个很好的学习起点,通过实践可以了解Acegi的基本用法,包括用户认证、权限控制、配置文件的理解以及如何与Spring框架集成。在实际项目中,我们需要根据需求进行更复杂的...

    java文集

    映射标记 Java的“静态库链接” 姚博文 集成ACEGI 进行权限控制 SWT可交互式Browser控件 JDK配置(注意) RIA简介(第一部分) 在 Eclipse 中嵌入 NASA World Wind Java SDK, 用3DES加密解密 ...

    acegi

    - **授权(Authorization)**:Acegi 提供细粒度的权限控制,允许开发者根据角色、URL路径、方法参数等进行权限配置,实现不同级别的访问控制。 - **会话管理(Session Management)**: Acegi 可以监控和管理用户...

    acegi 例子 进行了扩展

    Acegi Security的核心在于提供细粒度的权限控制,允许开发者定义谁可以访问哪些资源,以及他们可以进行哪些操作。这包括用户身份验证(登录)、角色分配、访问控制列表(ACL)等。 在“acegi-test”这个压缩包子...

    acegi实现用户权限

    AceGI可以通过配置实现基于角色的访问控制(RBAC)或基于权限的访问控制(PBAC)。 在实际应用中,AceGI的配置通常在Spring的配置文件中完成,通过定义SecurityContextHolder策略、定义安全过滤器链、设置认证和...

Global site tag (gtag.js) - Google Analytics