Spring Security 作为一款能够为基于Spring的企业应用提供一种强大和灵活的安全访问控制解决方案的框架,使开发人员不必编写大量的安全代码,即能为企业应用程序提供身份验证和授权等服务。Operamasks作为一个MVC框架,安全和认证一直是其未涉足领域.本文试图提供一种Operamasks和Spring Security整合的方案,以弥补这种不足。
通过上面的简介我们可以得知Spring Security 是一个基于Spring的强大的安全框架,而我们的Operamasks作为一个强大的MVC框架,如果能把这两者强强联合,不失为一件美事。现在我们就以最简单,最易上手的方式来一步步整合我们的Operamasks和Spring Security。以下我们将会建立一个小示例来介绍整合过程:
首先先下载Spring Security的包,本文的示例是在Spring Security 2.0.4 的环境下测试的,因为下载的是Spring Security 2.0.4的包,具体地址为:http://sourceforge.net/project/showfiles.php?group_id=73357&package_id=270072&release_id=630203,下完后会得到spring-security-2.0.4.zip,解压该包,进入该包下的dist目录,为了快速获得所需的lib包,我们只需找到dist目录下的spring-security-samples-tutorial-2.0.4.war,然后将其解压,到WEB-INF\lib目录下,把其目录下所有夹包先拷到另一个目录待备用。spring-security-samples-tutorial-2.0.4.war是Spring Security的官方示例,里面有运行环境所需的包,因为到其目录下拷贝。
好了,我们已经把包准备好了,接下来打开Operamasks Studio,新建一个Apusic工程并命名为aom_springsecurity,为其添加web模块,接着我们把3.1中拷贝出来的待备用的包全部拷到aom_springsecurity工程的lib目录下,然后在WEB-INF目录下建立spring 的配置文件applicationContext.xml,到此就准备开始配置了。
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/applicationContext.xml
</param-value>
</context-param>
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>
org.springframework.web.filter.DelegatingFilterProxy
</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>FORWARD</dispatcher>
<dispatcher>REQUEST</dispatcher>
</filter-mapping>
<welcome-file-list>
<welcome-file>enter.xhtml</welcome-file>
</welcome-file-list>把上述配置加到web.xml中。
配置说明:listener和context-param的配置是标准spring的配置,是为加载applicationContext.xml用的,在此就不多说
了。而下面的filter和filter-mapping则是Spring Security的配置,所有的用户在访问项目之前,都要先通过Spring Security的检测,这从第一时间把没有授权的请求排除在系统之外,保证系统资源的安全,welcome-file定义一个入口页面。
配置完web.xml 后,我们开始在WebContent根目录下建立几个测试页面,先建立enter.xhtml,代码如下:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE HTML PUBLIC "" ""> <f:view xmlns="http://www.w3.org/1999/xhtml" xmlns:f="http://java.sun.com/jsf/core" xmlns:w="http://www.apusic.com/jsf/widget" xmlns:layout="http://www.apusic.com/jsf/layout" xmlns:h="http://java.sun.com/jsf/html" xmlns:ajax="http://www.apusic.com/jsf/ajax" renderKitId="AJAX"> <w:head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> </w:head> <w:page title="Operamasks与Spring Security整合示例"> <a href="admin.faces">受保护页面</a> <a href="index.faces">普通页面</a> </w:page> </f:view>
该页面是入口页面,页面上有两个链接,一个是受保护页面,一个是普通页面,点击受保护页面链接会进入权限保护,只有有权限的人才能进入,普通页面则是任何人都可以访问的。接下来建立admin.xhtml,代码如下:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE HTML PUBLIC "" ""> <f:view xmlns="http://www.w3.org/1999/xhtml" xmlns:f="http://java.sun.com/jsf/core" xmlns:w="http://www.apusic.com/jsf/widget" xmlns:layout="http://www.apusic.com/jsf/layout" xmlns:h="http://java.sun.com/jsf/html" xmlns:ajax="http://www.apusic.com/jsf/ajax" renderKitId="AJAX"> <w:head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> </w:head> <w:page title="Operamasks与Spring Security整合示例"> 恭喜你,你通过了验证进入了一个受保护的页面。 </w:page> </f:view>
该页面是受保护页面,最后我们建立index.xhtml页面,代码如下:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE HTML PUBLIC "" ""> <f:view xmlns="http://www.w3.org/1999/xhtml" xmlns:f="http://java.sun.com/jsf/core" xmlns:w="http://www.apusic.com/jsf/widget" xmlns:layout="http://www.apusic.com/jsf/layout" xmlns:h="http://java.sun.com/jsf/html" xmlns:ajax="http://www.apusic.com/jsf/ajax" renderKitId="AJAX"> <w:head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> </w:head> <w:page title="Operamasks与Spring Security整合示例"> 这是一个任何人都可以访问的页面。 </w:page> </f:view>
至此,我们所有页面都建完了,现在到了最关键的一步了:配置权限。
还记得我们前面步骤曾经建立了一个applicationContext.xml吧,spring的精髓在于通过配置就可获得很多功能,权限也不例外。我们的需求是,受保护页面admin.xhtml必须有管理员的权限才可查看,普通页面index.xhtml则是任何用户都可以查看,因此我们只需在applicationContext.xml文件里加入以下代码:
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/security"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-2.0.4.xsd">
<!-- 设置权限 -->
<http auto-config='true'>
<intercept-url pattern="/admin.faces" access="ROLE_ADMIN" />
</http>
<!-- 定义角色 -->
<authentication-provider>
<user-service>
<user name="admin" password="admin" authorities="ROLE_ADMIN" />
</user-service>
</authentication-provider>
</beans:beans>
怎么样?很精简吧,从上面代码可以看出定义了一个“admin”的具有ROLE_ADMIN权限的用户,然后只有ROLE_ADMIN权限的用户才能访问admin.faces页面。
好了,到此为止,一个Operamasks与Spring Security整合的最简示例完成了,接下来我们启动我们的Apusic应用服务器部署我们的aom_springsecurity工程,然后打开以下网址:
http://127.0.0.1:6888/aom_springsecurity/enter.faces 或 http://127.0.0.1:6888/aom_springsecurity 即可看到以下页面:
经过上面的实践,是不是觉得很好入门呢?但有人可能还存在一些疑问,比如说登陆页面哪里来的?从来都没有建过这个页面啊?呵呵,的确我们从来没有建过这个页面,这个登录页面是Spring Security 自动生成的,在Spring Security 2.0后会自动生成,这是为了避免自定义登录页面所引起的其他问题才加入的。但又有人说了,这个默认登录页面太丑了,难道就不能自己定义一个吗?肯定可以,下面我们来介绍如何自定义登录页面:
首先,我们肯定要有自己的登录页面,新建一个login.xhtml页面,在新建login.xhtml页面的同时也新建了一个LoginBean,代码如下:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE HTML PUBLIC "" ""> <f:view xmlns="http://www.w3.org/1999/xhtml" xmlns:f="http://java.sun.com/jsf/core" xmlns:w="http://www.apusic.com/jsf/widget" xmlns:layout="http://www.apusic.com/jsf/layout" xmlns:h="http://java.sun.com/jsf/html" xmlns:ajax="http://www.apusic.com/jsf/ajax" renderKitId="AJAX"> <w:head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> </w:head> <w:page title="Operamasks与Spring Security整合示例"><w:form prependId="false">
<w:textField id="j_username" fieldLabel="用户名:" /> <w:textField id="j_password" fieldLabel="密码:" inputType="password" /> <w:button id="login" value="登录" /> </w:form> </w:page> </f:view>
package demo;
import java.io.IOException;
import java.io.Serializable;
import javax.faces.context.FacesContext;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.operamasks.faces.annotation.Action;
import org.operamasks.faces.annotation.ManagedBean;
import org.operamasks.faces.annotation.ManagedBeanScope;
@ManagedBean(name = "loginBean", scope = ManagedBeanScope.REQUEST)
public class LoginBean implements Serializable {
@Action(id = "login")
public void login() {
ServletContext servletContext = (ServletContext) FacesContext.getCurrentInstance().getExternalContext().getContext();
HttpServletRequest request = (HttpServletRequest) FacesContext.getCurrentInstance().getExternalContext().getRequest();
HttpServletResponse respone = (HttpServletResponse) FacesContext.getCurrentInstance().getExternalContext().getResponse();
RequestDispatcher rd = servletContext.getRequestDispatcher("/j_spring_security_check");
try {
rd.forward(request, respone);
} catch (ServletException e) {
// should log exception
} catch (IOException e) {
// should log exception
} finally {
FacesContext.getCurrentInstance().responseComplete();
}
}
} | j_spring_security_check 是form提交的action,这个action会被Spring Security拦截。 |
| 根据提交的用户名和密码转向到 j_spring_security_check 这个action。 |
| 跳过OperaMasks的生命周期,直接到渲染阶段。 |
也许有人会问,怎么LoginBean里面没有任何的验证逻辑?是的,我们用这个LoginBean的目的是,收集登录页面提交的用户名和密码,然后把它转向Spring Security 的验证框架去验证,这样我们只需编写页面即可,接下来就是配置Spring Security 用我们的登录页面,而不用默认的登录页面。
前面工作做好后,我们就修改applicationContext.xml文件,以便验证时进入我们的登录页面,修改后代码如下:
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/security"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-2.0.4.xsd">
<!-- 设置权限 -->
<http auto-config='true'>
<intercept-url pattern="/admin.faces" access="ROLE_ADMIN" />
<!-- 自定义登陆页面 -->
<form-login login-page="/login.faces" authentication-failure-url="/login.faces" />
</http>
<!-- 定义角色 -->
<authentication-provider>
<user-service>
<user name="admin" password="admin" authorities="ROLE_ADMIN" />
</user-service>
</authentication-provider>
</beans:beans>到此,我们配置完了,是不是很简单呢?然后我们再次打开http://127.0.0.1:6888/aom_springsecurity/enter.faces 或http://127.0.0.1:6888/aom_springsecurity,点击受保护页面链接后即可看到:
呵呵,是不是看到我们自己定义的登录页面了。
还记得前面我们把权限都定义在applicationContext.xml中吧,但现实应用中,我们的权限信息一般放在数据库里,下面我们将提供一种简单模型,把权限信息存在数据库里。
首先,我们先建立一个数据库springsecurity(本示例基于mysql 5.0),在这个数据库里建两张表并插入测试数据,一张是authorities(角色表),一张是user(用户表),这两张表的表名不能改,因为在默认情况下,spring security会默认读这两张表,脚本如下:
CREATE DATABASE springsecurity;
CREATE TABLE `users` (
`username` varchar(50) NOT NULL,
`password` varchar(50) NOT NULL,
`enabled` tinyint(1) NOT NULL,
PRIMARY KEY (`username`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
insert into `users`(`username`,`password`,`enabled`) values ('admin','admin',1);
CREATE TABLE `authorities` (
`username` varchar(50) NOT NULL,
`authority` varchar(50) NOT NULL,
UNIQUE KEY `ix_auth_username` (`username`,`authority`),
CONSTRAINT `FK_authorities` FOREIGN KEY (`username`) REFERENCES `users` (`username`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
insert into `authorities`(`username`,`authority`) values ('admin','ROLE_ADMIN');在上面我们已经创建数据源了,我们接下来要做的就是在applicationContext.xml配置数据源让Spring Security验证权限时从数据库读取权限信息,把applicationContext.xml中原先定义的权限信息删掉或注释掉,加入连接数据库的配置,修改后如下:
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/security"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-2.0.4.xsd">
<!-- 设置权限 -->
<http auto-config='true'>
<intercept-url pattern="/admin.faces" access="ROLE_ADMIN" />
<!-- 自定义登陆页面 -->
<form-login login-page="/login.faces" authentication-failure-url="/login.faces" />
</http>
<!-- 权限信息放在数据库中 -->
<authentication-provider>
<jdbc-user-service data-source-ref="dataSource" />
</authentication-provider>
<beans:bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<beans:property name="driverClassName" value="com.mysql.jdbc.Driver" />
<beans:property name="url" value="jdbc:mysql://localhost:3306/springsecurity?useUnicode=true&characterEncoding=UTF-8" />
<beans:property name="username" value="root" />
<beans:property name="password" value="root" />
</beans:bean>
</beans:beans>好了,配置完后就大功告成了,再次访问http://127.0.0.1:6888/aom_springsecurity/enter.faces 或http://127.0.0.1:6888/aom_springsecurity,是不是和之前把权限定义在文件中的一样呢?
本节中只是对Operamasks与Spring Security进行整合提供一个入门级的例子,更多详细的配置请访问Operamasks官方网站和Spring Security官方网站。