Spring Security 3.0 权限管理

深海的孤独

贡献于2011-11-09

字数:22948 关键词: Spring Security 安全相关框架

 Spring Security 3.0 权限管理 参考文献: 1、www.family168.com中的spring security权限管理手册。 2、spring security3.0权限管理手册 3、spring的相关资料。 本文档内容仅仅作为公司权限管理资料用,对于企业来说,权限管理将是系统中的非常重要的一个模块,权限的设计也是参考相关资料进行整理和补充。系统将通过数据库进行管理用户权限。 权限管理搭建要的问题: 1、区分Authentication(验证)与 Authorization(授权) 验证 这个用户是谁? 用户身份可靠吗? 授权 某用户A是否可以访问资源R 某用户A是否可以执行M操作 某用户A是否可以对资源R执行M操作 2、SS中的验证特点 支持多种验证方式 支持多种加密格式 支持组件的扩展和替换 可以本地化输出信息 3、SS中的授权特点 支持多种仲裁方式 支持组件的扩展和替换 支持对页面访问、方法访问、对象访问的授权。 4、SS核心安全实现 Web安全 通过配置Servlet Filter激活SS中的过滤器链 实现Session一致性验证 实现免登陆验证(Remember-Me验证) 提供一系列标签库进行页面元素的安全控制 方法安全 通过AOP模式实现安全代理 Web安全与方法安全均可以使用表达式语言定义访问规则 5、配置SS 配置Web.xml,应用安全过滤器 配置Spring,验证与授权部分 在web页面中获取用户身份 在web页面中应用安全标签库 实现方法级安全 6、配置web.xml 7、Spring配置文件中设置命名空间 8、通过数据库验证用户身份 9、完善web页面验证规则 10、自定义验证配置 11、本地化消息输出(国际化) 根据公司项目的开发要求和集合spring security3.0功能,公司将通过数据库进行对用户身份验证和授权,系统将建立5个基础表进行对权利的管理。 第一部分 数据库设计 1、表设计 表1:用户表(pub_users) 序号 字段 类型 含义 备注 1 User_Id Vchar(32) 用户id PK 2 user_account Vchar(30) 登陆用户名(登陆号) 3 User_name Vchar(40) 用户姓名 4 user_Password Vchar(100) 用户密码 5 Enabled Int 是否被禁用 0禁用1正常 6 isSys Int 是否是超级用户 0非1是 7 user_DESc Vchar(100) 描述 说明:pub_users表中的登录名和密码用来控制用户的登录。 表2:权限表(pub_authorities) 序号 字段 类型 含义 备注 1 authority_Id Vchar(32) 权限id PK 2 Authority_name Vchar(40) 权限名称 3 Authority_DESc Vchar(100) 权限描述 4 Enabled Int 是否被禁用 0禁用1正常 5 isSys Int 是否是超级权限 0非1是 说明:pub_authorities表中描述的是系统拥有哪些权限,如果要详细分类,可以将一个url定义一个权限,那样就能对所有资源进行管理。 表3:角色表(pub_roles) 序号 字段 类型 含义 备注 1 role_Id Vchar(32) 角色id PK 2 role_name Vchar(100) 角色名称 3 role_DESc Vchar(100) 角色描述 4 Enabled Int 是否被禁用 0禁用1正常 5 isSys Int 是否是超级权限 0非1是 说明:pub_roles表中描述的是系统按用户分类或按照功能模块分类,将系统进行整合归类管理 。 表4:资源表(pub_resources) 序号 字段 类型 含义 备注 1 resource_Id Vchar(32) 资源id PK 2 resource_name Vchar(100) 资源名称 3 resource _type Vchar(40) 资源类型 url、method 4 priority int 资源优先权 即排序 5 resource _string Vchar(200) 资源链接 6 resource_DESc Vchar(100) 资源描述 7 Enabled Int 是否被禁用 0禁用1正常 8 isSys Int 是否是超级权限 0非1是 说明:pub_roles表中描述的是系统需要保护的资源及(url或方法)。 以上四个表是权限管理的基础表(用户表、权限表、角色表、资源表)。 表5:用户角色连接表(pub_users_roles) 序号 字段 类型 含义 备注 1 Id Indetity Id主键 PK 2 user_Id Vchar(32) 用户id 3 role_id Vchar(32) 角色id 说明:用来管理用户和角色的关系。 表6:角色权限连接表(pub_roles_authorities) 序号 字段 类型 含义 备注 1 Id Indetity Id主键 PK 2 role _Id Vchar(32) 角色id 3 authority_Id Vchar(32) 权限id 说明:用来管理角色和权限的关系。 表7:权限资源连接表(pub_authorities_resources) 序号 字段 类型 含义 备注 1 Id Indetity Id主键 PK 2 authority_Id Vchar(32) 权限id 3 resource_Id Vchar(32) 资源id 说明:用来管理角色和权限的关系。 2、建表语句如下(数据库采用MS SQL 2000): create table pub_users( user_id varchar(32), user_account varchar(30), user_name varchar(40), user_password varchar(100), user_desc varchar(100), enabled int, issys int ); alter table pub_users add constraint pk_pub_users primary key(user_id); create table pub_authorities( authority_id varchar(32), authority_name varchar(40), authority_desc varchar(100), enabled int, issys int ); alter table pub_authorities add constraint pk_pub_authorities primary key(authority_id); create table pub_roles( role_id varchar(32), role_name varchar(40), role_desc varchar(100), enabled int, issys int ); alter table pub_roles add constraint pk_pub_roles primary key(role_id); create table pub_resources( resource_id varchar(32), resource_name varchar(100), resource_desc varchar(100), resource_type varchar(40), resource_string varchar(200), priority int, enabled int, issys int ); alter table pub_resources add constraint pk_pub_resources primary key(resource_id); create table pub_users_roles( id numeric(12,0) IDENTITY NOT NULL, user_id varchar(32), role_id varchar(32), enabled int ); alter table pub_users_roles add constraint pk_pub_users_roles primary key(id); alter table pub_users_roles add constraint fk_users_roles_users foreign key(user_id) references pub_users(user_id); alter table pub_users_roles add constraint fk_users_roles_roles foreign key(role_id) references pub_roles(role_id); create table pub_roles_authorities( id numeric(12,0) IDENTITY NOT NULL, role_id varchar(32), authority_id varchar(32), enabled int ); alter table pub_roles_authorities add constraint pk_pub_roles_authorities primary key(id); alter table pub_roles_authorities add constraint fk_pub_roles_authorities_authorities foreign key(authority_id) references pub_authorities(authority_id); alter table pub_roles_authorities add constraint fk_pub_roles_authorities_roles foreign key(role_id) references pub_roles(role_id); create table pub_authorities_resources( id numeric(12,0) IDENTITY NOT NULL, authority_id varchar(32), resource_id varchar(32), enabled int ); alter table pub_authorities_resources add constraint pk_pub_authorities_resources primary key(id); alter table pub_authorities_resources add constraint fk_pub_authorities_resources_authorities foreign key(authority_id) references pub_authorities(authority_id); alter table pub_authorities_resources add constraint fk_pub_authorities_resources_resources foreign key(resource_id) references pub_resources(resource_id); 3、E-R图如下: 第二部分 WEB数据库整合 提示:相关代码请参考项目模块 1、将数据库表结构和Hibernate建立映射,本系统采用annotation进行对数据库进行零配置处理(请参考hibernate映射),如图。 2、建立权限的Dao层。 3、建立权限的Service层 4、配置web.xml rstframe webAppRootKey rstframe.root log4jConfigLocation classpath:log4j.properties log4jRefreshInterval 60000 contextConfigLocation classpath*:/applicationContext.xml, classpath*:/applicationContext-rstframe.xml encodingFilter org.springframework.web.filter.CharacterEncodingFilter encoding UTF-8 encodingFilter /* hibernateOpenSessionInViewFilter com.rstco.frame.modules.orm.hibernate.OpenSessionInViewFilter excludeSuffixs js,css,jpg,gif hibernateOpenSessionInViewFilter /* springSecurityFilterChain org.springframework.web.filter.DelegatingFilterProxy springSecurityFilterChain /* struts2Filter org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter struts2Filter /* org.springframework.web.context.ContextLoaderListener org.springframework.web.util.Log4jConfigListener org.springframework.web.util.IntrospectorCleanupListener org.springframework.security.web.session.HttpSessionEventPublisher 20 index.jsp java.lang.Throwable /common/500.jsp 500 /common/500.jsp 404 /common/404.jsp 403 /common/403.jsp /WEB-INF/struts-menu-el.tld /WEB-INF/tlds/struts-menu-el.tld /WEB-INF/struts-menu.tld /WEB-INF/tlds/struts-menu.tld /WEB-INF/c.tld /WEB-INF/tlds/c.tld /WEB-INF/fmt.tld /WEB-INF/tlds/fmt.tld /WEB-INF/fn.tld /WEB-INF/tlds/fn.tld /WEB-INF/web-date.tld /WEB-INF/tlds/web-date.tld /WEB-INF/web-flex.tld /WEB-INF/tlds/web-flex.tld /WEB-INF/web-graph.tld /WEB-INF/tlds/web-graph.tld /WEB-INF/web-grid.tld /WEB-INF/tlds/web-grid.tld /WEB-INF/web-html.tld /WEB-INF/tlds/web-html.tld /WEB-INF/web-list.tld /WEB-INF/tlds/web-list.tld /WEB-INF/web-loushang.tld /WEB-INF/tlds/web-loushang.tld /WEB-INF/web-menu.tld /WEB-INF/tlds/web-menu.tld /WEB-INF/web-multitab.tld /WEB-INF/tlds/web-multitab.tld /WEB-INF/web-seltree.tld /WEB-INF/tlds/web-seltree.tld /WEB-INF/web-tab.tld /WEB-INF/tlds/web-tab.tld /WEB-INF/web-tree.tld /WEB-INF/tlds/web-tree.tld /WEB-INF/web-widgets.tld /WEB-INF/tlds/web-widgets.tld /WEB-INF/web-i18n.tld /WEB-INF/tlds/web-i18n.tld /WEB-INF/gystudio.tld /WEB-INF/tlds/gystudio.tld rar application/rar 5、配置spring security3.0中的xml文件 文件名:applicationContext-security.xml SpringSecurity安全配置 第三部分 SS3.0的实现 这是项目的主体部分: 这四个类说明如下。 一、 用来获得用户验证信息(MyUserDetailService) 代码如下: package com.rstco.frame.pub.security.support; import java.util.ArrayList; import java.util.Collection; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.dao.DataAccessException; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.userdetails.User; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.stereotype.Service; import com.rstco.frame.pub.security.dao.PubAuthoritiesResourcesDao; import com.rstco.frame.pub.security.dao.PubUsersDao; import com.rstco.frame.pub.security.entity.PubAuthorities; import com.rstco.frame.pub.security.entity.PubAuthoritiesResources; //你就可以从数据库中读入用户的密码,角色信息,是否锁定,账号是否过期 @Service public class MyUserDetailService implements UserDetailsService { @Autowired private PubUsersDao pubUsersDao; @Autowired private PubAuthoritiesResourcesDao pubAuthoritiesResourcesDao; public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException, DataAccessException { Collection auths=new ArrayList(); //取得用户的权限 List auth=pubUsersDao.findAuthByUserName(username); String password=null; //取得用户的密码 password=pubUsersDao.findUserByname(username).get(0).getUserPassword(); List aaa=pubAuthoritiesResourcesDao.getAll(); User user = new User(username, password, true, true, true, true, auths); return user; } } 二、 最核心的地方,就是提供某个资源对应的权限定义,取得所有角色(auth)的对应资源数据(MyInvocationSecurityMetadataSourceService) 代码如下: package com.rstco.frame.pub.security.support; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import javax.servlet.ServletContext; import org.hibernate.Query; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.security.access.ConfigAttribute; import org.springframework.security.access.SecurityConfig; import org.springframework.security.web.FilterInvocation; import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource; import org.springframework.security.web.util.AntUrlPathMatcher; import org.springframework.security.web.util.UrlMatcher; import org.springframework.stereotype.Service; import com.rstco.frame.modules.orm.hibernate.HibernateDao; import com.rstco.frame.pub.security.dao.PubAuthoritiesResourcesDao; import com.rstco.frame.pub.security.entity.PubAuthorities; import com.rstco.frame.pub.security.entity.PubResources; /* * * 最核心的地方,就是提供某个资源对应的权限定义,即getAttributes方法返回的结果。 * 注意,我例子中使用的是AntUrlPathMatcher这个path matcher来检查URL是否与资源定义匹配, * 事实上你还要用正则的方式来匹配,或者自己实现一个matcher。 * * 此类在初始化时,应该取到所有资源及其对应角色的定义 * * 说明:对于方法的spring注入,只能在方法和成员变量里注入, * 如果一个类要进行实例化的时候,不能注入对象和操作对象, * 所以在构造函数里不能进行操作注入的数据。 */ @Service public class MyInvocationSecurityMetadataSourceService implements FilterInvocationSecurityMetadataSource { @Autowired private PubAuthoritiesResourcesDao pubAuthoritiesResourcesDao; private UrlMatcher urlMatcher = new AntUrlPathMatcher(); private static Map> resourceMap = null; public MyInvocationSecurityMetadataSourceService() { loadResourceDefine(); } /* private void loadResourceDefine() { resourceMap = new HashMap>(); Collection atts = new ArrayList(); ConfigAttribute ca = new SecurityConfig("ROLE_ADMIN"); atts.add(ca); resourceMap.put("/index.jsp", atts); resourceMap.put("/i.jsp", atts); }*/ private void loadResourceDefine() { ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); SessionFactory sessionFactory = (SessionFactory)context.getBean("sessionFactory"); Session session = sessionFactory.openSession(); List query=session.createSQLQuery("select authority_name from pub_authorities ").list(); resourceMap = new HashMap>(); Collection atts = new ArrayList(); //List auths =session.createQuery(arg0); //pubAuthoritiesResourcesDao.findAuthAll(); for (String auth : query) { ConfigAttribute ca = new SecurityConfig(auth);// "ROLE_ADMIN" // atts.add(ca); List query1=session.createSQLQuery("select resource_string " + "from Pub_Authorities_Resources,Pub_Resources, Pub_authorities " + "where Pub_Authorities_Resources.resource_id=Pub_Resources.resource_id and " + " Pub_Authorities_Resources.resource_id=Pub_authorities.authority_id and " + " Authority_name='"+auth+"'").list(); for (String res : query1) { String url = res; // 判断资源文件和权限的对应关系,如果已经存在,要进行增加 if (resourceMap.containsKey(url)) { Collection value = resourceMap.get(url); value.add(ca); resourceMap.put(url, value); // "log.jsp","role_user,role_admin" } else { atts.add(ca); resourceMap.put(url, atts); } resourceMap.put(url, atts); } } } // According to a URL, Find out permission configuration of this URL. public Collection getAttributes(Object object) throws IllegalArgumentException { // guess object is a URL. String url = ((FilterInvocation) object).getRequestUrl(); Iterator ite = resourceMap.keySet().iterator(); while (ite.hasNext()) { String resURL = ite.next(); if (urlMatcher.pathMatchesUrl(url, resURL)) { return resourceMap.get(resURL); } } return null; } public boolean supports(Class clazz) { return true; } public Collection getAllConfigAttributes() { return null; } } 三、 最重要的是decide方法,如果不存在对该资源的定义,直接放行;否则,如果找到正确的角色,即认为拥有权限,并放行,否则throw new AccessDeniedException("no right");这样,就会进入上面提到的403.jsp页面。(MyAccessDecisionManager) 代码如下: package com.rstco.frame.pub.security.support; import java.util.Collection; import java.util.Iterator; import org.springframework.security.access.AccessDecisionManager; import org.springframework.security.access.AccessDeniedException; import org.springframework.security.access.ConfigAttribute; import org.springframework.security.access.SecurityConfig; import org.springframework.security.authentication.InsufficientAuthenticationException; import org.springframework.security.core.Authentication; import org.springframework.security.core.GrantedAuthority; public class MyAccessDecisionManager implements AccessDecisionManager { //In this method, need to compare authentication with configAttributes. // 1, A object is a URL, a filter was find permission configuration by this URL, and pass to here. // 2, Check authentication has attribute in permission configuration (configAttributes) // 3, If not match corresponding authentication, throw a AccessDeniedException. public void decide(Authentication authentication, Object object, Collection configAttributes) throws AccessDeniedException, InsufficientAuthenticationException { if(configAttributes == null){ return ; } System.out.println(object.toString()); //object is a URL. Iterator ite=configAttributes.iterator(); while(ite.hasNext()){ ConfigAttribute ca=ite.next(); String needRole=((SecurityConfig)ca).getAttribute(); for(GrantedAuthority ga:authentication.getAuthorities()){ if(needRole.equals(ga.getAuthority())){ //ga is user's role. return; } } } throw new AccessDeniedException("no right"); } public boolean supports(ConfigAttribute attribute) { // TODO Auto-generated method stub return true; } public boolean supports(Class clazz) { return true; } } 四、 这个过滤器要插入到授权之前。最核心的代码就是invoke方法中的InterceptorStatusToken token = super.beforeInvocation(fi);这一句,即在执行doFilter之前,进行权限的检查,而具体的实现已经交给accessDecisionManager了(MyFilterSecurityInterceptor) 代码如下: package com.rstco.frame.pub.security.interceptor; import java.io.IOException; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.access.AccessDecisionManager; import org.springframework.security.access.SecurityMetadataSource; import org.springframework.security.access.intercept.AbstractSecurityInterceptor; import org.springframework.security.access.intercept.InterceptorStatusToken; import org.springframework.security.web.FilterInvocation; import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource; public class MyFilterSecurityInterceptor extends AbstractSecurityInterceptor implements Filter { private FilterInvocationSecurityMetadataSource securityMetadataSource; public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { FilterInvocation fi = new FilterInvocation(request, response, chain); invoke(fi); } public FilterInvocationSecurityMetadataSource getSecurityMetadataSource() { return this.securityMetadataSource; } public Class getSecureObjectClass() { return FilterInvocation.class; } public void invoke(FilterInvocation fi) throws IOException, ServletException { InterceptorStatusToken token = super.beforeInvocation(fi); try { fi.getChain().doFilter(fi.getRequest(), fi.getResponse()); } finally { super.afterInvocation(token, null); } } @Override public SecurityMetadataSource obtainSecurityMetadataSource() { return this.securityMetadataSource; } public void setSecurityMetadataSource( FilterInvocationSecurityMetadataSource securityMetadataSource) { System.out.println("abc=======================edf"); this.securityMetadataSource = securityMetadataSource; } public void destroy() { // TODO Auto-generated method stub } public void init(FilterConfig filterconfig) throws ServletException { // TODO Auto-generated method stub } } 如有异议,请加qq:89168934,互相学习交流。

下载文档,方便阅读与编辑

文档的实际排版效果,会与网站的显示效果略有不同!!

需要 15 金币 [ 分享文档获得金币 ]
21 人已下载

下载文档

相关文档