在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. Leetcode884.Uncommon Words from Two Sentences两句话中的不常见单词

    给定两个句子 A 和 B . (句子是一串由空格分隔的单词.每个单词仅由小写字母组成.) 如果一个单词在其中一个句子中只出现一次,在另一个句子中却没有出现,那么这个单词就是不常见的. 返回所有不常用单 ...

  2. ThinkPHP5.0中的build.php自动生成所需的目录结构的详细方法

    一.来到根目录下,找到bulid.php文件进行改写. 改写方法:保留常用的目录结构,其余按照需求改吧! 二.复制一份build.php文件到application目录下 此时根目录下的bulid.p ...

  3. Minitab软件是现代质量管理统计的领先者,全球六西格玛实施的共同语言,以无可比拟的强大功能和简易的可视化操作深受广大质量学者和统计专家的青睐。

    Minitab软件是现代质量管理统计的领先者,全球六西格玛实施的共同语言,以无可比拟的强大功能和简易的可视化操作深受广大质量学者和统计专家的青睐. MINITAB 功能菜单包括:基础和高级统计工具: ...

  4. 基于OSS+DataLakeAnalytics+QuickBI的Serverless的查询分析和可视化BI

    基于OSS的数据查询分析和可视化BI报表 数据存储在OSS后,有多种查询分析的方法,包括阿里云MaxCompute.DataLakeAnalytics产品等Severless查询分析服务,也可以自建S ...

  5. 中国境内PE\VC\投资公司名单

    中国境内PE\VC\投资公司名单 1.青云创投 2.高盛 3.红杉资本 4.鼎晖创投 5.枫丹国际 6.派杰投资银行 7.凯雷投资 8.长安私人资本 9.格林雷斯 10.汉能资本 11.启明创投 12 ...

  6. MVC设计之从零打造到实际操作(总汇)

    我们为什么要自己搭建一个MVC架构的框架? 1.为了更快的开发效率 2.为了更高的运行效率 3.为了更好的证明自己 在别的框架中,有些方法我们使用起来可能会比较麻烦,我们可以在自己的框架中写一些自己想 ...

  7. Introduction to 3D Game Programming with DirectX 12 学习笔记之 --- 第十章:混合

    原文:Introduction to 3D Game Programming with DirectX 12 学习笔记之 --- 第十章:混合 代码工程地址: https://github.com/j ...

  8. nginx 做反向代理

    1.Nginx的常用配置大家可以去搜一下,有很多优秀的博客,我这篇文章要实现的需求是: a.根据访问的域名不同,跳转到不同的项目(html首页,80端口) b.拦截访问中所有带有api的请求,转发到后 ...

  9. json 2016-09-18 22:03 207人阅读 评论(18) 收藏

    JSON:JavaScript 对象表示法(JavaScript Object Notation) JSON是什么? JSON(JavaScript Object Notation) 是一种轻量级的数 ...

  10. shell学习(18)- split切分文件命令

    Linux split命令用于将一个文件分割成数个. 该指令将大文件分割成较小的文件,在默认情况下将按照每1000行切割成一个小文件. 语法: split [--help][--version][-& ...