首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 软件管理 > 软件架构设计 >

Spring Security 3.0配备参考

2012-06-26 
Spring Security 3.0配置参考MyEclipse中Spring Security 3.0.3无废话配置(第一章):http://andy-ghg.iteye

Spring Security 3.0配置参考
MyEclipse中Spring Security 3.0.3无废话配置(第一章):http://andy-ghg.iteye.com/blog/1071639
MyEclipse中Spring Security 3.0.3无废话配置(第二章):http://andy-ghg.iteye.com/blog/1081622
Spring Security应用实例(一):用户登录 : http://sunjiesh.iteye.com/blog/365907
Spring Security3.1 最新配置实例: http://blog.csdn.net/k10509806/article/details/6369131
spring security 3 自定义认证,授权示例 http://chen-rojer-gmail-com.iteye.com/blog/1037973

xml被扫描顺序参考: http://sence-qi.iteye.com/blog/1328902
由于服务器启动时的加载配置文件的顺序为web.xml---root-context.xml(Spring的配置文件)---servlet-context.xml(SpringMVC的配置文件),由于root-context.xml配置文件中Controller会先进行扫描装配,但是此时service还没有进行事务增强处理,得到的将是原样的Service(没有经过事务加强处理,故而没有事务处理能力)


先按照http://panyongzheng.iteye.com/blog/1475762这里配置完SpringMVC&Hibernate,在增加spring能力时,同时选择spring security jar,并实现全注解方式。注意:service.impl里面的类,如是要是先回滚,那应该throws RuntimeException。

MyEclipse中Spring Security 3.0.3无废话配置


第一件事,下载中文说明文档,搜索一下就能找到。
第二件事,找到官方原版英文说明文档,搜索一下就能找到。
第三件事,需要注意的问题:
1.请使用MyEclipse 自带的Spring 3与Spring Security 3(以下简称SS3),我的MyEclipse是8.6,自带的版本是SS3.0.3。
2.登录的表单用户名必须是j-username,密码必须是j-password,表单的action必须是"/你的项目/j_spring_security_check",这里是否可以定制,我不清楚。
3.MyEclise 8.6自带的Hibernate与Spring与SS3之间没有任何Jar包冲突,出现问题请不要怀疑Jar包的问题。(至少我的目前为止没有任何冲突)
4.注意头文件,Spring的头文件是:
applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>  <beans xmlns="http://www.springframework.org/schema/beans"      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"      xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"      xsi:schemaLocation="        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd      http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">  </beans> 


SS3的头文件是
applicationContext-security.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-3.0.xsd       http://www.springframework.org/schema/security       http://www.springframework.org/schema/security/spring-security-3.0.xsd">  </beans:beans> 


5.Spring security 3的Filter一定要在Struts2后面,否则表单提交会首先被Struts2拦截,会有可能出现异常。

好了,正式配置开始。
第一步:配置web.xml
在web.xml中加入Spring以及SS3的参数如下:
<!--Spring的ApplicationContext 载入 -->      <listener>          <listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>      </listener>      <listener>          <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>      </listener>      <context-param>          <param-name>contextConfigLocation</param-name>          <param-value>classpath:applicationContext.xml</param-value>      </context-param>        <!-- SpringSecurity filter-->      <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>      </filter-mapping>
 

第二步:加入SS3配置文件
在applicationContext.xml中加载SS3的配置文件,在文件最末加上以下代码(路径自己决定,但是要保证能加载到SS3的配置文件):
<import resource="applicationContext-security.xml"/> 


第三步:最简单的运行配置
为SS3的配置文件加上最简单的配置,让整个项目能运行起来,在SS3配置文件中加入如下代码(头文件请参考上面的代码):
<http auto-config='true'>      <intercept-url pattern="/**" access="ROLE_USER" />  </http>  


运行一下,会报错,是否说没有配置<authentication-manager>?如果不是,请解决掉问题否则进入下一步
第四步:配置<authentication-manager>
在SS3的配置文件中加入以下代码:
<authentication-manager>      <authentication-provider>          <user-service>              <user name="jimi" password="jimispassword" authorities="ROLE_USER, ROLE_ADMIN" />              <user name="bob" password="bobspassword" authorities="ROLE_USER" />          </user-service>      </authentication-provider>  </authentication-manager> 


再次运行,如果没有出错,则进入下一步,否则请解决掉错误。

第五步:访问我们的项目
打开浏览器输入项目的URL地址,然后定位到index.jsp,这时候你会发现页面被强制定位到了一个登录界面,虽然难看,但是代表我们成功了,尝试输入用户名:jimi,密码:jimispassword,点击登录按钮,是否跳转到index.jsp(你得保证你项目里确实有这个页面)?
右键查看源代码,找到它的表单各项的名称、action等信息,下面备用。

第六步:定制我们自己的登录界面
新建login.jsp,Form的提交方式一定是post,否则无法提交或者提交不执行,然后在SS3.0的配置文件中的http标签中加入配置,最终如下所示:
<http auto-config='true' access-denied-page="/common/403.jsp">          <intercept-url pattern="/css/**" filters="none" />          <intercept-url pattern="/images/**" filters="none" />          <intercept-url pattern="/login.jsp*" access="IS_AUTHENTICATED_ANONYMOUSLY" />                  <form-login login-page='/login.jsp' />          <intercept-url pattern="/**" access="ROLE_USER" /> />      </http>
 

common/403.jsp代表当用户没有权限的时候跳转到这个页面,form-login标签内就是指向你自定义的登录界面。配置完毕后,再次运行项目,输入URL,这时就会跳转到你的自定义登录界面了。输入帐号密码,点击登录,功能与刚才看到的一样(表单设计请参考第三件事中的第2小段文字)。



上回说到数据库验证首先看以往的验证配置:
<authentication-manager>        <authentication-provider>            <user-service>                <user name="jimi" password="jimispassword" authorities="ROLE_USER, ROLE_ADMIN" />                <user name="bob" password="bobspassword" authorities="ROLE_USER" />            </user-service>        </authentication-provider>    </authentication-manager>  
 

现在我们要用数据库来验证。
第一步:建立数据库
这里只用两张表即可解决问题,也许你看过很多建立五张到七张的,那是实际在项目中才这样做,我们做试验的话在这里只建立两张表:1.用户表2.资源表。
用户表四个字段:ID、USERNAME、PASSWORD、ROLE(权限)
资源表有三个字段:ID、资源路径、访问权限
资源路径就是一个URL地址,访问权限就是这个资源需要什么样子的权限才能访问。


第二步:权限提供
package cn.com.fri.security.supports;    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.annotation.PostConstruct;    import org.springframework.beans.factory.annotation.Autowired;  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 org.springframework.transaction.annotation.Transactional;    import cn.com.fri.security.dao.interfaces.IAuthoritiesDAO;  import cn.com.fri.security.dao.interfaces.IResourcesDAO;  import cn.com.fri.security.vo.Authorities;  import cn.com.fri.security.vo.Resources;    /**  *   * 此类在初始化时,应该取到所有资源及其对应角色的定义  *   */  @Service("securityMetadataSource")  public class MyInvocationSecurityMetadataSource implements          FilterInvocationSecurityMetadataSource {      @Autowired      private IAuthoritiesDAO authoritiesDAO;      @Autowired      private IResourcesDAO resourcesDAO;        private UrlMatcher urlMatcher = new AntUrlPathMatcher();;      private static Map<String, Collection<ConfigAttribute>> resourceMap = null;        public MyInvocationSecurityMetadataSource() {      }        /**      * 在此处,将数据库中所有的资源以及对应的权限加入到内存中      */      @PostConstruct      public void loadResourceDefine() {          resourceMap = new HashMap<String, Collection<ConfigAttribute>>();          Collection<ConfigAttribute> atts = new ArrayList<ConfigAttribute>();          System.out.println(authoritiesDAO);          List<Authorities> auth = authoritiesDAO.findAll();          for (Authorities au : auth) {              ConfigAttribute ca = new SecurityConfig(au.getAuthorname());              atts.add(ca);          }          List<Resources> res = resourcesDAO.findAll();          for (Resources resources : res) {              resourceMap.put(resources.getResourcesstring(), atts);          }          System.out.println("权限加载完毕");      }        // According to a URL, Find out permission configuration of this URL.      @Transactional(readOnly = true)      public Collection<ConfigAttribute> getAttributes(Object object)              throws IllegalArgumentException {          // guess object is a URL.          String url = ((FilterInvocation) object).getRequestUrl();          Iterator<String> 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<ConfigAttribute> getAllConfigAttributes() {          return null;      }        public void setAuthoritiesDAO(IAuthoritiesDAO authoritiesDAO) {          this.authoritiesDAO = authoritiesDAO;      }        public void setResourcesDAO(IResourcesDAO resourcesDAO) {          this.resourcesDAO = resourcesDAO;      }    } 


找个类的作用就是在服务器启动的时候将存放在数据库表中的资源与访问权限加载到内存中去。

第三步:编写路径验证类:
package cn.com.fri.security.supports;    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;  import org.springframework.stereotype.Service;  @Service("myAccessDecisionManagerBean")  public class MyAccessDecisionManager implements AccessDecisionManager {        public void decide(Authentication authentication, Object object,              Collection<ConfigAttribute> configAttributes)              throws AccessDeniedException, InsufficientAuthenticationException {          if (configAttributes == null) {              return;          }                    Iterator<ConfigAttribute> 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;      }    } 


此类用户判断当前登录的用户是否有权限访问某个路径。而这里路径的访问权限就是从内存中取出来的。
第四步:登录验证:
package cn.com.fri.security.supports;    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.authority.GrantedAuthorityImpl;  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 org.springframework.transaction.annotation.Transactional;    import cn.com.fri.security.dao.interfaces.IUsersDAO;  import cn.com.fri.security.vo.Authorities;  import cn.com.fri.security.vo.CustomUser;  import cn.com.fri.security.vo.Users;    @Service("userDetailsService")  public class UserDetailsServiceImpl implements UserDetailsService {        @Autowired      private IUsersDAO dao;        @Transactional(readOnly = true)      public UserDetails loadUserByUsername(String username)              throws UsernameNotFoundException, DataAccessException {          System.out.println(username);          Users user = dao.findByUsername(username).get(0);//此查询由自己去实现          if (user == null)              throw new UsernameNotFoundException("user not found");          Collection<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();            List<Authorities> auths = dao.findAutByUsername(username);//此查询由自己去实现如果用户表中已经包含了权限,就无需进行这一步操作了。          System.out.println(">>>>>>获得的权限有:" + auths.size() + "个");          for (Authorities a : auths) {              GrantedAuthorityImpl authorityImpl = new GrantedAuthorityImpl(a                      .getAuthorname());              authorities.add(authorityImpl);          }          CustomUser u = new CustomUser(username, user.getPsw(), user                  .getEnabled(), true, true, true, authorities);          u.setUser(user);          return u;      }  } 


在这个类中,用户一旦登录,我们就能获取到用户的权限,将用户权限放入到CustomUser中,然后返回这个CustomUser即可。CustomUser为继承自org.springframework.security.core.userdetails.User的一个类,继承的原因是为了让原来的User能够拥有更多的属性,例如用户的中文名称等等。里面的List<Authorities> auths = dao.findAutByUsername(username);这一步是因为我是按照七张表的结构去建立的,因此如果你只有两张表,这里完全可以省略。你甚至可以在这里写死(试验用)如下:
GrantedAuthorityImpl authorityImpl = new GrantedAuthorityImpl("ROLE_ADMIN");  authorities.add(authorityImpl); 


第五步:配置SS3的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-3.0.xsd       http://www.springframework.org/schema/security       http://www.springframework.org/schema/security/spring-security-3.0.xsd">      <http auto-config='true' access-denied-page="/common/403.jsp">          <!-- 以下为不需要权限就能访问的资源**意思就是包括子目录也同样适用 -->          <intercept-url pattern="/css/**" filters="none" />          <intercept-url pattern="/app/**" filters="none" />          <intercept-url pattern="/images/**" filters="none" />          <intercept-url pattern="/swf/**" filters="none" />          <intercept-url pattern="/login.jsp*" access="IS_AUTHENTICATED_ANONYMOUSLY" />          <form-login login-page='/login.jsp' default-target-url="/index.do"              always-use-default-target="true" />          <!-- 配置退出登录 -->          <logout invalidate-session="true" logout-url="/logout"              logout-success-url="/login.jsp" />          <session-management invalid-session-url="/error.html">              <concurrency-control max-sessions="1"                  expired-url="/error.html" />          </session-management>          <!--             配置登录验证,包括权限的启动都在这里:         -->          <custom-filter before="FILTER_SECURITY_INTERCEPTOR" ref="myFilter" />      </http>            <!-- 配置登录验证的类 -->      <beans:bean id="daoAuthenticationProvider"          ref="userDetailsService" />      </beans:bean>        <beans:bean id="authenticationManager"          />              </beans:list>          </beans:property>      </beans:bean>            <authentication-manager>          <authentication-provider user-service-ref="userDetailsService">          </authentication-provider>      </authentication-manager>          <!--          一个自定义的filter,必须包含authenticationManager,accessDecisionManager,securityMetadataSource三个属性,          我们的所有控制将在这三个类中实现,这里使用了annocation,所以ref后面的参数在XML配置中是没有的,详细看这三个类。      -->      <beans:bean id="myFilter"          ref="authenticationManager" />          <beans:property name="accessDecisionManager" ref="myAccessDecisionManagerBean" />          <beans:property name="securityMetadataSource" ref="securityMetadataSource" />      </beans:bean>    </beans:beans>
 


由于东西较多,所以再一开始的时候建议大家去下载官方的说明文档和中文翻译的说明文档。
在此我们的配置结束。这一部分虽然代码比较多,但是其实一点不复杂,仔仔细细的看一遍就会了。









热点排行