在SpringSide 3的官方文档中,说安全框架使用的是Spring Security 2.0。乍一看,吓了我一跳,以为Acegi这么快就被淘汰了呢。上搜索引擎一搜,发现原来Spring Security 2.0就是Acegi 2.0。悬着的心放下来了。虽然SpringSide 3中关于Acegi的配置文件看起来很不熟悉,但是读了Acegi 2.0的官方文档后,一切都释然了。

先来谈一谈Acegi的基础知识,Acegi的架构比较复杂,但是我希望我下面的只言片语能够把它说清楚。大家都知道,如果要对Web资源进行保护,最好的办法莫过于Filter,要想对方法调用进行保护,最好的办法莫过于AOP。Acegi对Web资源的保护,就是靠Filter实现的。如下图:


一般来说,我们的Filter都是配置在web.xml中,但是Acegi不一样,它在web.xml中配置的只是一个代理,而真正起作用的Filter是作为Bean配置在Spring中的。web.xml中的代理依次调用这些Bean,就实现了对Web资源的保护,同时这些Filter作为Bean被Spring管理,所以实现AOP也很简单,真的是一举两得啊。

Acegi中提供的Filter不少,有十多个,一个一个学起来比较复杂。但是对于我们Web开发者来说,常用的就那么几个,如下图中的被红圈圈标记出来的:


从上到下,它们实现的功能依次是1、制定必须为https连接;2、从Session中提取用户的认证信息;3、退出登录;4、登录;5、记住用户;6、所有的应用必须配置这个Filter。

一般来说,我们写Web应用只需要熟悉这几个Filter就可以了,如果不需要https连接,连第一个也不用熟悉。但是有人肯定会想,这些Filter怎么和我的数据库联系起来呢?不用着急,这些Filter并不直接处理用户的认证,也不直接处理用户的授权,而是把它们交给了认证管理器和决策管理器。如下图:

对于这两种管理器,那也是不需要我们写代码的,Acegi也提供了现成的类。那么大家又奇怪了:又是现成的,那怎么和我的数据库关联起来呢?别着急,其实这两个管理器自己也不做事,认证管理器把任务交给了Provider,而决策管理器则把任务交给了Voter,如下图:

现在我要告诉你们,这里的Provider和Voter也是不需要我们写代码的。不要崩溃,快到目标了。Acegi提供了多个Provider的实现类,如果我们想用数据库来储存用户的认证数据,那么我们就选择DaoAuthenticationProvider。对于Voter,我们一般选择RoleVoter就够用了,它会根据我们配置文件中的设置来决定是否允许某一个用户访问制定的Web资源。

而DaoAuthenticationProvider也是不直接操作数据库的,它把任务委托给了UserDetailService,如下图:


而我们要做的,就是实现这个UserDetailService。图画得不好,大家不要见笑,但是说了这么多总算是引出了我们开发中的关键,那就是我们要实现自己的UserDetailService,它就是连接我们的数据库和Acegi的桥梁。UserDetailService的要求也很简单,只需要一个返回org.springframework.security.userdetails.User对象的loadUserByUsername(String userName)方法。因此,怎么设计数据库都可以,不管我们是用一个表还是两个表还是三个表,也不管我们是用户-授权,还是用户-角色-授权,还是用户-用户组-角色-授权,这些具体的东西Acegi统统不关心,它只关心返回的那个User对象,至于怎么从数据库中读取数据,那就是我们自己的事了。

反过来再看看上面的过程,我们发现,即使我们要做的只是实现自己的UserDetailService类,但是我们不得不在Spring中配置那一大堆的Bean,包括几个Filter,几个Manager,几个Provider和Voter,而这些配置往往都是重复的无谓的。好在Acegi 2.0也认识到了这个问题,所以,它设计了一个<http>标签,让Acegi的配置得到了简化。下面是SpringSide 3中的配置的截图,大家可以看看:


下图是官方文章中的传统Filter设置和<http>元素之间的对应关系:


下面的代码是SpringSide 3中实现UserDetailService的范例,在SpringSide 3的范例中,白衣使用了三个表User、Role、Authority。但是Acegi不关心你用了几个表,它只关心UserDetails对象。而决定用户能否访问指定Web资源的,是RoleVoter类,无需任何修改它可以工作得很好,唯一的缺点是它只认ROLE_前缀,所以搞得白衣的Authority看起来都象角色,不伦不类。

package
 personal.youxia.service.security;

import
 java.util.ArrayList;

import
 java.util.List;

import
 org.springframework.beans.factory.annotation.Required;

import
 org.springframework.dao.DataAccessException;

import
 org.springframework.security.GrantedAuthority;

import
 org.springframework.security.GrantedAuthorityImpl;

import
 org.springframework.security.userdetails.UserDetails;

import
 org.springframework.security.userdetails.UserDetailsService;

import
 org.springframework.security.userdetails.UsernameNotFoundException;

import
 personal.youxia.entity.user.Authority;

import
 personal.youxia.entity.user.Role;

import
 personal.youxia.entity.user.User;

import
 personal.youxia.service.user.UserManager;

/**

* 实现SpringSecurity的UserDetailsService接口,获取用户Detail信息.
 * 
 * 
@author
 calvin
 
*/

public
 
class
 UserDetailServiceImpl 
implements
 UserDetailsService {

    
private
 UserManager userManager;

    
public
 UserDetails loadUserByUsername(String userName) 
throws
 UsernameNotFoundException, DataAccessException {
        User user 
=
 userManager.getUserByLoginName(userName);
        
if
 (user 
==
 
null
)
            
throw
 
new
 UsernameNotFoundException(userName 
+
 
"
 不存在
"
);

        List
<
GrantedAuthority
>
 authsList 
=
 
new
 ArrayList
<
GrantedAuthority
>
();

        
for
 (Role role : user.getRoles()) {
            
for
 (Authority authority : role.getAuths()) {
                authsList.add(
new
 GrantedAuthorityImpl(authority.getName()));
            }
        }

        
//
 目前在MultiDatabaseExample的User类中没有enabled, accountNonExpired,credentialsNonExpired, accountNonLocked等属性
        
//
 暂时全部设为true,在需要时才添加这些属性.

org.springframework.security.userdetails.User userdetail 
=
 
new
 org.springframework.security.userdetails.User(
                user.getLoginName(), user.getPassword(), 
true

true

true

true
, authsList
                        .toArray(
new
 GrantedAuthority[authsList.size()]));

        
return
 userdetail;
    }

    @Required
    
public
 
void
 setUserManager(UserManager userManager) {
        
this
.userManager 
=
 userManager;
    }
}

最后再来说说这个命名的问题,我对Authentication和Authority这两个单词比较反感,两个原因,一是因为它们太生僻了,二是因为它们长得太像了,明明一个是认证,一个是授权,意思相差很远,外貌却如此相似,确实很烦人。如果让我来选择,我喜欢Privilege这个单词,在我刚使用MySQL的时候就跟它很熟了,所以在我的项目中,我可能会用Privilege来代替Authority。如果我们只使用User-Role两级关系,使用RoleVoter默认的ROLE_前缀当然没有关系,如果是像白衣这样是用三层关系,最好还是把这个前缀改一改,以免混淆。
原文地址:http://www.blogjava.net/youxia/archive/2008/12/07/244883.html

SpringSide 3 中的安全框架的更多相关文章

  1. 《Entity Framework 6 Recipes》中文翻译系列 (20) -----第四章 ASP.NET MVC中使用实体框架之在MVC中构建一个CRUD示例

    翻译的初衷以及为什么选择<Entity Framework 6 Recipes>来学习,请看本系列开篇 第四章  ASP.NET MVC中使用实体框架 ASP.NET是一个免费的Web框架 ...

  2. 《Entity Framework 6 Recipes》中文翻译系列 (21) -----第四章 ASP.NET MVC中使用实体框架之在页面中创建查询和使用ASP.NET URL路由过虑

    翻译的初衷以及为什么选择<Entity Framework 6 Recipes>来学习,请看本系列开篇 4.2. 构建一个搜索查询 搜索数据是几乎所有应用的一个基本功能.它一般是动态的,因 ...

  3. eclipse中SSH三大框架环境搭建<三>

    相关链接: eclipse中SSH三大框架环境搭建<一> eclipse中SSH三大框架环境搭建<二> 引言:通过上两篇文章我们已经可以掌握struts2和spring的环境的 ...

  4. eclipse中SSH三大框架环境搭建<二>

    通过上一篇博客我们可以轻松搭建strtus2的环境,接下来由我来继续介绍spring的环境搭建以及spring注入的简单使用 相关链接:eclipse中SSH三大k框架环境搭建<一> ec ...

  5. 细数.NET 中那些ORM框架 —— 谈谈这些天的收获之一

    细数.NET 中那些ORM框架 —— 谈谈这些天的收获之一(转) ADO.NET Entity Framework        ADO.NET Entity Framework 是微软以 ADO.N ...

  6. eclipse中SSH三大框架环境搭建<一>

    这里先简单介绍一下我用的三大框架版本以及下载地址 相关链接:eclipse中SSH三大框架环境搭建<二> eclipse中SSH三大框架环境搭建<三> struts-2.3.3 ...

  7. Android 进阶 Android 中的 IOC 框架 【ViewInject】 (下)

    上一篇博客我们已经带大家简单的吹了一下IoC,实现了Activity中View的布局以及控件的注入,如果你不了解,请参考:Android 进阶 教你打造 Android 中的 IOC 框架 [View ...

  8. IOS 中的CoreImage框架

    IOS 中的CoreImage框架(framework) - time4cnblogs 时间 2014-03-15 00:24:00  博客园-所有随笔区原文  http://www.cnblogs. ...

  9. ethtool 在 Linux 中的实现框架和应用

    转载:http://www.ibm.com/developerworks/cn/linux/1304_wangjy_ethtools/index.html?ca=dat- 王 俊元, 软件工程师, I ...

随机推荐

  1. Facebook iOS App如何优化启动时间

    http://www.cocoachina.com/ios/20160105/14870.html 提高 Facebook 应用的性能已经成为 Facebook 持续关注的领域.因为我们相信一个高性能 ...

  2. 链表源代码(C语言实现)

    源代码(C语言实现) ①.构造链表节点 typedef struct Node    //一个单独的节点                   {                         int ...

  3. 【JZOJ4803】【NOIP2016提高A组模拟9.28】求导

    题目描述 输入 输出 样例输入 2x^2+3x+1 样例输出 4x+3 数据范围 样例解释 求导的意思: 多项式是由若干个单项式构成的 单项式的一般形式是ax^b,其中ab都是常数,x是自变量 对于单 ...

  4. 【数论】不定方程&逆元&中国剩余定理

    一.不定方程 要求逆元,首先要知道什么是不定方程. 已知a,b,c,求解x,y,形如ax + by = c 的方程就是不定方程. 不定方程有两种解的情况: 1.无解 2.存在且有无限的解 那么,如何判 ...

  5. PLAY2.6-SCALA(四) 请求体解析器

    一个http请求是一个请求头后面跟着一个请求体,头部信息比较短,可以安全的缓存在内存中,在Play中头部信息使用RequestHeader类进行建模.请求体的内容可能较大,使用流stream的形式进行 ...

  6. JavaScript学习之setTimeout

    <JavaScript权威指南>第四版中说“window对象方法setTimeout()用来安排一个JavaScript的代码段在将来的某个指定时间运行”. setTimeout(foo, ...

  7. flask 与celery

    在flask 中使用celery 是特别简单的,celery官网都没有特别介绍如何使用. 使用celery首先要知道怎么配置celery.   1. 实例化celery celery = Celery ...

  8. Flask第一篇

    一. Python 现阶段三大主流Web框架 Django Tornado Flask 对比 1.Django 主要特点是大而全,集成了很多组件,例如: Models Admin Form 等等, 不 ...

  9. POJ-1125_Stockbroker Grapevine

    Stockbroker Grapevine Time Limit: 1000MS Memory Limit: 10000K Description Stockbrokers are known to ...

  10. @codechef - SONATR@ Sonya and Tree

    目录 @description@ @solution@ @accepted code@ @details@ @description@ 给定 p 为 0~N-1 的一个排列,并给定一棵 N 个点的树. ...