Operamasks与Spring Security的整合
2009-07-21 由 sunboy 发表   评论(6条)   有4641人浏览

1. 概述

Spring Security 做为一款能够为基于Spring的企业应用提供一种强大和灵活的安全访问控制解决方案的框架,使开发人员不必编写大量的安全代码,即能为企业应用程序提供身份验证和授权等服务。Operamasks做为一个MVC框架,安全和认证一直是其未涉足领域.本文试图提供一种Operamasks和Spring Security整合的方案,以弥补这种不足。

2. Spring Security 简介

SpringSecurity是一个能够为基于Spring的企业应用系统提供描述性安全访问控制解决方案的安全框架。它提供了一组可以在Spring应用上下文中配置的Bean,充分利用了Spring IoC(依赖注入,也称控制反转)和AOP(面向切面编程)功能,为应用系统提供声明式的安全访问控制功能,减少了为企业系统安全控制编写大量重复代码的工作。Spring Security的前身是Acegi Security,Acegi Security 为Spring Framework提供一个兼容的安全认证服务,是Spring 下属的子项目,2007年底,正式成为spring 的组合项目,并更名为Spring Security。

3. 开始整合

通过上面的简介我们可以得知Spring Security 是一个基于Spring的强大的安全框架,而我们的Operamasks作为一个强大的MVC框架,如果能把这两者强强联合,不失为一件美事。现在我们就以最简单,最易上手的方式来一步步整合我们的Operamasks和Spring Security。以下我们将会建立一个小示例来介绍整合过程:

3.1. 下载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是SpringSecurity的官方示例,里面有运行环境所需的包,因为到其目录下拷贝。

3.2. 建立一个aom_springsecurity项目

好了,我们已经把包准备好了,接下来打开Operamasks Studio,新建一个Apusic工程并命名为aom_springsecurity,为其添加web模块,接着我们把3.1中拷贝出来的待备用的包全部拷到aom_springsecurity工程的lib目录下,然后在WEB-INF目录下建立spring 的配置文件applicationContext.xml,到此就准备开始配置了。

3.3. 配置web.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则是Spirng Security的配置,所有的用户在访问项目之前,都要先通过Spring Security的检测,这从第一时间把没有授权的请求排除在系统之外,保证系统资源的安全,welcome-file定义一个入口页面。

3.4. 建立页面

配置完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>

至此,我们所有页面都建完了,现在到了最关键的一步了:配置权限。

3.5. 配置权限

还记得我们前面步骤曾经建立了一个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 即可看到以下页面:

 

4. 自定义登录页面

经过上面的实践,是不是觉得很好入门呢?但有人可能还存在一些疑问,比如说登陆页面哪里来的?从来都没有建过这个页面啊?呵呵,的确我们从来没有建过这个页面,这个登录页面是Spring Security 自动生成的,在Spring Security 2.0后会自动生成,这是为了避免自定义登录页面所引起的其他问题才加入的。但又有人说了,这个默认登录页面太丑了,难道就不能自己定义一个吗?肯定可以,下面我们来介绍如何自定义登录页面:

4.1. 建立页面和ManageBean

首先,我们肯定要有自己的登录页面,新建一个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整合示例">
      1<w:form prependId="false">
        2<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>
1

prependId="false" 是为了告诉AOM,用户自己定义组件ID。

2

j_username ,j_password 这两个ID是供Spring Security 验证时用的。

 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();
       1RequestDispatcher rd = servletContext.getRequestDispatcher("/j_spring_security_check");
       try {
         2rd.forward(request, respone);
       } catch (ServletException e) {
        // should log exception
       } catch (IOException e) {
        // should log exception
       } finally {
         3FacesContext.getCurrentInstance().responseComplete();
       }
    }
 }
1

j_spring_security_check 是form提交的action,这个action会被Spring Security拦截。

2

根据提交的用户名和密码转向到 j_spring_security_check 这个action。

3

跳过AOM的生命周期,直接到渲染阶段。

也许有人会问,怎么LoginBean里面没有任何的验证逻辑?是的,我们用这个LoginBean的目的是,收集登录页面提交的用户名和密码,然后把它转向Spring Security 的验证框架去验证,这样我们只需编写页面即可,接下来就是配置Spring Security 用我们的登录页面,而不用默认的登录页面。

4.2. 配置我们的登录页面

前面工作做好后,我们就修改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" />

            <!-- 自定义登陆页面 -->
            1<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>
1

login-page属性定义了我们的登录页面,authentication-failure-url属性定义了我们验证错误后跳回登录页面。

到此,我们配置完了,是不是很简单呢?然后我们再次打开http://127.0.0.1:6888/aom_springsecurity/enter.faces 或http://127.0.0.1:6888/aom_springsecurity,点击受保护页面链接后即可看到:

呵呵,是不是看到我们自己定义的登录页面了。

5. 数据库权限

还记得前面我们把权限都定义在applicationContext.xml中吧,但现实应用中,我们的权限信息一般放在数据库里,下面我们将提供一种简单模型,把权限信息存在数据库里。

5.1. 建立数据源

首先,我们先建立一个数据库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');

5.2. 配置数据源

在上面我们已经创建数据源了,我们接下来要做的就是在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>
      1<jdbc-user-service data-source-ref="dataSource" />
    </authentication-provider>

    2<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&amp;characterEncoding=UTF-8" />
      <beans:property name="username" value="root" />
      <beans:property name="password" value="root" />
    </beans:bean>
  </beans:beans>
1

定义一个jdbc-user-service,然后赋给他一个数据源,这样在验证时,Spring Security会根据数据源去查找权限信息。

2

定义一个数据源。

好了,配置完后就大功告成了,再次访问http://127.0.0.1:6888/aom_springsecurity/enter.faces 或http://127.0.0.1:6888/aom_springsecurity,是不是和之前把权限定义在文件中的一样呢?

6. 小结

本文中只是对Operamasks与Spring Security进行整合提供一个入门级的例子,更多详细的配置请访问Operamasks官方网站和Spring Security官方网站。

如果您对整合有兴趣了,可以直接下载使用或参考工程:aom_springsecurity.zip

所有评论
jijicyf 2010-10-22 评论道:
这个例子也有很大问题,如果先访问登录页面,输入用户名密码点击登录,是不会跳转到授权页面的。
bjljxxc 2010-05-27 评论道:
spring 3.0 spring security 3.0 无法照此法集成,主要是集成后不能跳转到相应页面。
mgsxy203 2009-12-15 评论道:
哎,这个页面都有点荒废了。 我看文章也是用IE6写的,有没有试试成功登陆后导航到一个文件夹中的页面呐?
mgsxy203 2009-11-22 评论道:
能讲下remember me和logout的实现?
mgsxy203 2009-11-22 评论道:
文中的用户表应该是users,而不是user吧?在oracle里可能建不了user表,我使用的是建users。在oracle里没有boolean字段,因此使用了number代替,并将数值设置为1表示enabled。测试可以使用。 要是文章再写的深入下好了。
mgsxy203 2009-11-15 评论道:
写个Security的系列吧,跟AOM集成的。比较完整的,比如到业务方法的控制层面、页面内容的显示等
1   共1页
您还没有登录,请登录后发表评论