Spring Security学习总结二.doc
《Spring Security学习总结二.doc》由会员分享,可在线阅读,更多相关《Spring Security学习总结二.doc(10页珍藏版)》请在得力文库 - 分享文档赚钱的网站上搜索。
1、SpringSecurity学习总结二前一篇文章里介绍了Spring Security的一些基础知识,相信你对Spring Security的工作流程已经有了一定的了解,如果你同时在读源代码,那你应该可以认识的更深刻。在这篇文章里,我们将对Spring Security进行一些自定义的扩展,比如自定义实现UserDetailsService,保护业务方法以及如何对用户权限等信息进行动态的配置管 理。 一 自定义UserDetailsService实现 UserDetailsService接口,这个接口中只定义了唯一的UserDetails loadUserByUsername(String u
2、sername)方法,它通过用户名来获取整个UserDetails对象。 前一篇文章已经介绍了系统提供的默认实现方式InMemoryDaoImpl,它从配置文件中读取用户的身份信息(用户名,密码等),如果你的客户想修改 用户信息,就需要直接修改配置文件(你需要告诉用户配置文件的路径,应该在什么地方修改,如何把明文密码通过MD5加密以及如何重启服务器等)。听起来是不是很费劲啊! 在实际应用中,我们可能需要提供动态的方式来获取用户身份信息,最常用的莫过于数据库了,当然也可以是LDAP服务器等。 本文首先介绍系统提供的一个默认实现类 JdbcDaoImpl(org.springframework.s
3、ecurity.userdetails.jdbc. JdbcDaoImpl),它通过用户名从数据库中获取用户身份信息,修改配置文件,将userDetailsService Bean的配置修改如下:1 JdbcDaoImpl类继承自Spring Framework的JdbcDaoSupport类并实现了UserDetailsService接口,因为从数据库中读取信息,所以首先需要一个数据 源对象,这里不在多说,这里需要重点介绍的是usersByUsernameQuery和authoritiesByUsernameQuery,属性, 它们的值都是一条SQL语句,JdbcDaoImpl类通过SQL从
4、数据库中检索相应的信息,usersByUsernameQuery属性定义了通过用 户名检索用户信息的SQL语句,包括用户名,密码以及用户是否可用,authoritiesByUsernameQuery属性定义了通过用户名检索用户 权限信息的SQL语句,这两个属性都引用一个MappingSqlQuery(请参考Spring Framework相关资料)实例,MappingSqlQuery的mapRow()方法将一个ResultSet(结果集)中的字段映射为一个领域对 象,Spring Security为我们提供了默认的数据库表,如下图所示(摘自Spring in Action): 图1 JdbcD
5、aoImp数据库表 如果我们需要获取用户的其它信息就需要自己来扩展系统的默认实现,首先应该了解一下UserDetailsService实现的原理,还是要回到源代码,以下是JdbcDaoImpl类的部分代码:1privateclassUsersByUsernameMappingextendsMappingSqlQuery3protectedUsersByUsernameMapping(DataSourceds)5super(ds,usersByUsernameQuery);7declareParameter(newSqlParameter(Types.VARCHAR);9compile();11
6、13protectedObjectmapRow(ResultSetrs,intrownum)throwsSQLException15Stringusername=rs.getString(1);17Stringpassword=rs.getString(2);19booleanenabled=rs.getBoolean(3);21UserDetailsuser=newUser(username,password,enabled,true,23 true,true,newGrantedAuthoritynewGrantedAuthorityImpl(HOLDER);25returnuser;26
7、28 也许你已经看出什么来了,对了,系统返回的UserDetails对象就是从这里来的,这就是读源代码的好 处,DaoAuthenticationProvider提供者通过调用自己的authenticate(Authentication authentication)方法将用户在登录页面输入的用户信息与这里从数据库获取的用户信息进行匹配,如果匹配成功则将用户的权限信息赋给 Authentication对象并将其存放在SecurityContext中,供其它请求使用。那么我们要扩展获得更多的用户信息,就要从这里下手了(数据库表这里不在列出来,可以参考项目的WebRoot/db目录下的schema
8、.sql文 件)。比如我们自己的数据库设计中是通过一个loginId和用户名来登录或者我们需要额外ID,EMAIL地址等信 息,MySecurityJdbcDaoImpl实现如下:1protectedclassUsersByUsernameMappingextendsMappingSqlQuery3protectedUsersByUsernameMapping(DataSourceds)5super(ds,usersByUsernameQuery);7declareParameter(newSqlParameter(Types.VARCHAR);9compile();1113protected
9、ObjectmapRow(ResultSetrs,intrownum)throwsSQLException15/TODOAuto-generatedmethodstub17StringuserName=rs.getString(1);19StringpassWord=rs.getString(2);21booleanenabled=rs.getBoolean(3);23IntegeruserId=rs.getInt(4);25Stringemail=rs.getString(5);27MyUserDetailsuser=newMyUser(userName,passWord,enabled,t
10、rue,28 true,true,newGrantedAuthoritynew29 GrantedAuthorityImpl(HOLDER);31user.setEmail(email);33user.setUserId(userId);35returnuser;3739 如果你已经看过源代码,你会发现这里只是其中的一部分代码 ,具体的实现请看项目的MySecurityJdbcDaoImpl类实现,以及MyUserDetails和MyUser类,这里步在一一列出。 如果使用Hibernate来操作数据库,你也可以从你的DAO中获取用户信息,最后你只要将存放了用户身份信息和权限信息的列表(Lis
11、t)返回给系统就可以。 每当用户请求一个受保护的资源时,就会调用认证管理器以获取用户认证信息,但是如果我们的用户信息保存在数据库中,那么每次请求都从数据库中获取信息将会 影响系统性能,那么将用户信息进行缓存就有必要了,下面就介绍如何在Spring Security中使用缓存。二缓存用户信息 查看AuthenticationProvider接口的实现类AbstractUserDetailsAuthenticationProvider抽 象类(我们配置文件中配置的DaoAuthenticationProvider类继承了该类)的源代码,会有一行代码:1UserDetailsuser=this.us
12、erCache.getUserFromCache(username); DaoAuthenticationProvider认证提供者使用UserCache接口的实现来实现对用户信息的缓存,修改DaoAuthenticationProvider的配置如下:1 这里我们加入了对userCache Bean的引用,userCache使用Ehcache来实现对用户信息的缓存。userCache配置如下:14811 我们这里使用的是EhCacheBasedUserCache,也就是用EhCache实现缓存的,另外系统还提供了一个默认的实现类NullUserCache类,我们可以通过源代码了解到,无论上面
13、使用这个类都返回一个null值,也就是不使用缓存。三保护业务方法 从第一篇文章中我们已经了解到,Spring Security使用Servlet过滤器来拦截用户的请求来保护WEB资源,而这里却是使用Spring 框架的AOP来提供对方法的声明式保护。它通过一个拦截器来拦截方法调用,并调用方法安全拦截器来保护方法。 在介绍之前,我们先回忆一下过滤器安全拦 截器是如何工作的。过滤器安全拦截器首先调用AuthenticationManager认证管理器认证用户信息,如果用过认证则调用 AccessDecisionManager访问决策管理器来验证用户是否有权限访问objectDefinitionSo
14、urce中配置的受保护资源。 首先看看如何配置方法安全拦截器,它和过滤器安全拦截器一方继承自AbstractSecurityInterceptor抽象类(请看源代码),如下:156 com.test.service.UserService.get*=ROLE_SUPERVISOR789 这段代码是不是很眼熟啊,哈哈,这和我们配置的过滤器安全拦截器几乎完全一样,方法安全拦截器的处理过程实际和过滤器安全拦截器的实现机制是相同的,这 里就在累述,详细介绍请参考中相关部分。但是也有不同的地方,那就是这里的objectDefinitionSource的配置,在等号前面的不在是URL资源, 而是需要保护的
15、业务方法,等号后面还是访问该方法需要的用户权限。我们这里配置的com.test.service.UserService.get*表 示对com.test.service包下UserService类的所有以get开头的方法都需要ROLE_SUPERVISOR权限才能调用。这里使 用了提供的实现方法MethodSecurityInterceptor,系统还给我们提供了aspectj的实现方式,这里不在介绍(我也正在学), 读者可以参考其它相关资料。 之前已经提到过了,Spring Security使用Spring 框架的AOP来提供对方法的声明式保护,即拦截方法调用,那么接下来就是创建一个拦截器,
16、配置如下:1345methodSecurityInterceptor678910userService111213 userService是我们在applicationContext.xml中配置的一个Bean,AOP的知识不是本文介绍的内容。到这里保护业务方法的配置就介绍完了。四将资源放在数据库中 现在,你的用户提出了新的需求,它们需要自己可以给系统用户分配或者取消权限。其实这个并不是什么新鲜事,作为开发者,你也应该为用户提供这样的功能。那 么我们就需要这些受保护的资源和用户权限等信息都是动态的,你可以选择把它们存放在数据库中或者LDAP服务器上,本文以数据库为例,介绍如何实现用户权 限的动
17、态控制。 通过前面的介绍,你可能也注意到了,不管是MethodSecurityInterceptor还是FilterSecurityInterceptor 都使用authenticationManager和accessDecisionManager属性用于验证用户,并且都是通过使用 objectDefinitionSource属性来定义受保护的资源。不同的是过滤器安全拦截器将URL资源与权限关联,而方法安全拦截器将业务方法与 权限关联。 你猜对了,我们要做的就是自定义这个objectDefinitionSource的实现,首先让我们来认识一下系统为我们提供的 ObjectDefinitionS
18、ource接口,objectDefinitionSource属性正是指向此接口的实现类。该接口中定义了3个方 法,ConfigAttributeDefinition getAttributes(Object object)方法用户获取保护资源对应的权限信息,该方法返回一个ConfigAttributeDefinition对象(位于 org.springframework.security包下),通过源代码我们可以知道,该对象中实际就只有一个List列表,我们可以通过使用 ConfigAttributeDefinition类的构造函数来创建这个List列表,这样,安全拦截器就通过调用 getAt
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- Spring Security学习总结二 Security 学习 总结
限制150内