一. 简单介绍
1.1 本文目的
集成Acegi到自己的项目中, 并且将用户信息和权限放到数据库, 提供方法允许权限动态变化,变化后自动加载最新的权限
本文介绍Acegi例子的时候采用的是acegi-security-samples-tutorial-1.0.6.war
阅读本文需要对Spring有一定的了解, 如果你还没有接触过, 有些地方可能不容易理解, 这时候可能需要参考本文后附的Spring地址, 先了解一下Spring的基本知识.
本文使用的是Mysql数据库, 如果你使用其他的数据库, 可能需要修改相应的SQL.
本文及所附的全部代码放在http://acegi-test.sourceforge.net/
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中不存在我们需要的userI