Spring-Security完整实例

1.收集资料

http://blog.csdn.net/k10509806/article/details/6369131

http://www.cnblogs.com/wenxiu/archive/2011/01/22/1942084.html

http://ootabc.iteye.com/blog/688213

http://wenku.baidu.com/view/abf23846336c1eb91a375d83.html

http://www.cnblogs.com/zhangliang0115/archive/2012/04/02/2429584.html

2.数据库建表

采用基于角色-资源-用户权限管理设计。

2.1.用户表    test_user


字段名


标示符


类型


有无空值


主键


备注


ID


ID


varchar(36)


NO


Y


编号


USERNAME


用户名


Varchar(30)


NO


PASSWORD


密码


varchar(36)


NO


STATUS


状态


tinyint


0开启、

1关闭

2.2.角色表    test_role


字段名


标示符


类型


有无空值


主键


备注


ID


ID


varchar(36)


NO


Y


编号


NAME


角色名


varchar(50)

2.3.资源表    test_resource


字段名


标示符


类型


有无空值


主键


备注


ID


ID


varchar(36)


NO


Y


编号


NAME


资源名称


varchar(50)


URL


地址


Varchar(50)


TYPE


类型


Tinyint

2.4.用户角色表   test_user_role


字段名


标示符


类型


有无空值


主键


备注


ID


ID


varchar(36)


NO


Y


编号


UID


用户ID


varchar(36)


RID


角色ID


varchar(36)

2.5.角色资源表   test_role_resource


字段名


标示符


类型


有无空值


主键


备注


ID


ID


varchar(36)


NO


Y


编号


RSID


资源ID


varchar(36)


RID


角色ID


varchar(36)

3.梳理资料,整理思路

3.1.Spring Security3.12种常见方式

Ø  用户信息和权限存储于数据库,而资源和权限的对应采用硬编码配置。

Ø  细分角色和权限,并将角色、用户、资源、权限均都存储于数据库中。并且自定义过滤器,代替原来的FilterSecurityInterceptor过滤器;并分别实现AccessDecisionManager、UserDetailsService和InvocationSecurityMetadataSourceService,并在配置文件中进行相应配置。

Ø发现两者不可结合使用,会有问题。

4.代码整理

接下来开始着手代码编写,不管是两种实现方式中的哪种方式,个人感觉都需要把加载用户信息放在一个类里面管理,直观方便,结构清晰,不要用在配置文件直接写sql语句。

4.1.资源和权限对应写在配置文件中

1、     web.xml配置

a)     启动时加载Spring的jdbc和security配置文件。

b)      配置spring的servlet过滤器,使其能够识别Spring Controller。

c)     加载Spring Security过滤器链代理,它按照顺序执行spring的权限过滤器。

d)     其他业务加载,比如:log4j,字符集编码过滤器,session超时等。

Xml代码  

  1. <?xml version="1.0" encoding="UTF-8"?>
    <web-app version="2.5"
        xmlns="http://java.sun.com/xml/ns/javaee"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
        http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">  
    
       <context-param>
            <param-name>webAppRootKey</param-name>
    10.         <param-value>springMvc</param-value>
    11.    </context-param>
    12.
    13.     <!-- Listener log4jConfigLocation -->
    14.     <listener>
    15.         <listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
    16.     </listener>
    17.
    18.   <context-param>
    19.     <param-name>contextConfigLocation</param-name>
    20.     <param-value>
    21.         classpath:/module/applicationContext-jdbc.xml,
    22.         classpath:/module/applicationContext-security.xml
    23.     </param-value>
    24.   </context-param>
    25.
    26.   <!-- Log4j -->
    27.   <context-param>
    28.     <param-name>log4jConfigLocation</param-name>
    29.     <param-value>classpath:/config/log4j.properties</param-value>
    30.   </context-param>
    31.
    32.   <listener>
    33.     <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    34.   </listener>
    35.
    36.   <!-- 权限过滤器链 -->
    37.   <filter>
    38.     <filter-name>springSecurityFilterChain</filter-name>
    39.     <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
    40.   </filter>
    41.
    42.   <filter-mapping>
    43.     <filter-name>springSecurityFilterChain</filter-name>
    44.     <url-pattern>/*</url-pattern>
    45.   </filter-mapping>
    46.
    47.   <servlet>
    48.         <servlet-name>springmvc</servlet-name>
    49.         <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    50.         <init-param>
    51.             <param-name>contextConfigLocation</param-name>
    52.             <param-value>classpath:/module/applicationContext-servlet.xml</param-value>
    53.         </init-param>
    54.         <load-on-startup>1</load-on-startup>
    55.     </servlet>
    56.
    57.     <servlet-mapping>
    58.         <servlet-name>springmvc</servlet-name>
    59.         <url-pattern>/</url-pattern>
    60.     </servlet-mapping>
    61.
    62.   <!-- Spring 刷新Introspector防止内存泄露 -->
    63.     <listener>
    64.         <listener-class>
    65.             org.springframework.web.util.IntrospectorCleanupListener
    66.         </listener-class>
    67.     </listener>
    68.
    69.     <!--  获取Spring Security session的生命周期-->
    70.     <listener>
    71.         <listener-class>
    72.             org.springframework.security.web.session.HttpSessionEventPublisher
    73.         </listener-class>
    74.     </listener>
    75.
    76.     <!-- session超时定义,单位为分钟 -->
    77.     <session-config>
    78.         <session-timeout>20</session-timeout>
    79.     </session-config>
    80.
    81.
    82.   <filter>
    83.     <filter-name>encodingFilter</filter-name>
    84.     <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
    85.   </filter>
    86.
    87.   <filter-mapping>
    88.     <filter-name>encodingFilter</filter-name>
    89.     <url-pattern>/*</url-pattern>
    90.   </filter-mapping>
    91.
    92.   <welcome-file-list>
    93.     <welcome-file>index.jsp</welcome-file>
    94.   </welcome-file-list>
    95. </web-app>  

2、  application-security.xml文件的配置。

   application-servlet.xml配置不懂的参考spring MVC3.0.5搭建全程。

Xml代码  

  1. <?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.1.xsd">  
    
      <http pattern="/resources/**" security="none"></http>
      <http pattern="/user/login" security="none"></http>
    10.
    11.   <http auto-config="true"
    12.         use-expressions="true"
    13.         access-denied-page="/user/denied">
    14.   <!--
    15.     default-target-url       指定了从登录页面登录后进行跳转的页面
    16.     always-use-default-target   true表示登录成功后强制跳转
    17.     authentication-failure-url  表示验证失败后进入的页面
    18.     login-processing-url       设置验证登录验证地址,如果不设置,默认是j_spring_security_check
    19.     username-parameter,password-parameter     设置登录用户名和密码的请求name,默认:j_username,j_password
    20.     default-target-url="/user/home"
    21.    -->
    22.     <form-login login-page="/user/login"
    23.                 always-use-default-target="true"
    24.                 authentication-failure-url="/user/login?error=1"
    25.                 login-processing-url="/logincheck"
    26.                 authentication-success-handler-ref="successHandler"/>
    27.
    28.     <intercept-url pattern="/user/myjsp" access="hasRole(‘ROLE_USER‘)"/>
    29.     <intercept-url pattern="/user/admin" access="hasRole(‘ROLE_ADMIN‘)"/>
    30.
    31.     <logout logout-url="/logout" logout-success-url="/user/login"/>
    32.     <!--
    33.          error-if-maximum-exceeded 后登陆的账号会挤掉第一次登陆的账号
    34.          session-fixation-protection  防止伪造sessionid攻击,用户登录成功后会销毁用户当前的session。
    35.     -->
    36.     <session-management invalid-session-url="/user/timedout" session-fixation-protection="none">
    37.         <concurrency-control max-sessions="1" error-if-maximum-exceeded="true"/>
    38.     </session-management>
    39.     <!-- <custom-filter ref="mySecurityFilter" before="FILTER_SECURITY_INTERCEPTOR"/> -->
    40.   </http>
    41.
    42.   <authentication-manager alias="authManager">
    43.     <authentication-provider user-service-ref="userServiceDetail">
    44.         <!--<jdbc-user-service data-source-ref="dataSource"
    45.                             authorities-by-username-query=""
    46.                             group-authorities-by-username-query=""/> -->
    47.         <password-encoder hash="md5">
    48.             <salt-source user-property="username"/>   <!-- 盐值  [添加这个属性后,加密密码明文为:"密码明文{盐值}"] -->
    49.         </password-encoder>
    50.
    51.     </authentication-provider>
    52.   </authentication-manager>
    53.
    54. </beans:beans>  

问题:

我自己写了个User实现UserDetails,发现同一个账号可以同时登陆,也就是说concurrency-control没有起到作用,参考了一下资料后,重写一下User的hashcode,equals方法就行了。【后来发现的问题,附件自己添加】

详细参考:http://flashing.iteye.com/blog/823666

Java代码  

  1. @Override
    public int hashCode() {
        return username.hashCode();
    }  
    
    @Override
    public boolean equals(Object obj) {
        User user = (User)obj;
        return this.username.equals(user.getUsername());
    10. }  

解析:

a、use-expressions

如:hasRole(‘ROLE_ADMIN’或hasIpAddress(‘127.0.0.1’))等,看不懂的可以参考下面链接。

http://static.springsource.org/spring-security/site/docs/3.0.7.RELEASE/reference/el-access.html

http://hougbin.iteye.com/blog/1526980

http://kongcodecenter.iteye.com/blog/1320021

b、<password-encoder  hash=”md5”>

其属性hash就是加密的方法是什么?常用的可能是md5和sha吧。

主要说下<salt-source user-property=’username’>盐值:不加这个属性,spring验证密码时,直接用MD5加密后的值,与我们自己写的实现了UserDetailsService接口的类中loadUsersByUsername(String username)方法返回的UserDetails中的密码进行比较;如果加了这个属性并且设置user-property=’username’[不知道能不能设置其他值,或许也可以设置password,没有尝试],加密前的明文就成为”密码明文{盐值}”,这里的盐值为用户名。

c、remember-me的实现策略参考下面:

http://static.springsource.org/spring-security/site/docs/3.0.x/reference/remember-me.html

http://blog.csdn.net/small_love/article/details/6641316

http://xyz20003.iteye.com/blog/223282

d、UserDetailsService可以通过手工设置几个用户的权限:

Java代码  

  1. <user-service id="userDetailsService">
  2. <user name="jimi" password="jimispassword" authorities="ROLE_USER, ROLE_ADMIN" />
  3. <user name="bob" password="bobspassword" authorities="ROLE_USER" />
  4. </user-service>

或者通过属性文件读取;

<user-service id="userDetailsService" properties="users.properties"/>

属性 文件内容格式为: username=password,grantedAuthority[,grantedAuthority][,enabled|disabled]

Java代码  

  1. jimi=jimispassword,ROLE_USER,ROLE_ADMIN,enabled
  2. bob=bobspassword,ROLE_USER,enabled

e、UserDetailsService实现类

Java代码  

  1. /**
     * @description  项目实现的用户查询服务,将用户信息查询出来(用于实现用户的认证)
     * @author aokunsang
     * @date 2012-8-15
     */
    public class MyUserDetailServiceImpl implements UserDetailsService {  
    
        private UserService userService;  
    
    10.     @Override
    11.     public UserDetails loadUserByUsername(String username)
    12.             throws UsernameNotFoundException {
    13.
    14.         System.out.println("---------MyUserDetailServiceImpl:loadUserByUsername------正在加载用户名和密码,用户名为:"+username);
    15.
    16.         User user = userService.loadUserByUserName(username);
    17.         if(user==null){
    18.             throw new UsernameNotFoundException("用户名没有找到!");
    19.         }
    20.
    21.         boolean enabled = true;                //是否可用
    22.         boolean accountNonExpired = true;        //是否过期
    23.         boolean credentialsNonExpired = true;
    24.         boolean accountNonLocked = true;
    25.
    26.         Set<GrantedAuthority> authorities = new HashSet<GrantedAuthority>();
    27.         //如果你使用资源和权限配置在xml文件中,如:<intercept-url pattern="/user/admin" access="hasRole(‘ROLE_ADMIN‘)"/>;
    28.         //并且也不想用数据库存储,所有用户都具有相同的权限的话,你可以手动保存角色(如:预订网站)。
    29.         //authorities.add(new SimpleGrantedAuthority("ROLE_USER"));
    30.
    31.         List<Role> roles = userService.findUserRolesByUsername(username);
    32.         for(Role role : roles){
    33.             GrantedAuthority ga = new SimpleGrantedAuthority(role.getName());
    34.             authorities.add(ga);
    35.         }
    36.         return new org.springframework.security.core.userdetails.User(
    37.                 user.getUserName(),
    38.                 user.getPassWord(),
    39.                 enabled,
    40.                 accountNonExpired,
    41.                 credentialsNonExpired,
    42.                 accountNonLocked,
    43.                 authorities);
    44.     }
    45.     /**
    46.      * @param userService the userService to set
    47.      */
    48.     public void setUserService(UserService userService) {
    49.         this.userService = userService;
    50.     }
    51.
    52. }  

4.2.资源和配置文件存储在数据库中

需要自己手动写一个拦截器,提供查询数据库中的资源权限,提供验证用户是否具有访问URL地址的权限(3个类)。

1、AbstractSecurityInterceptor继承类,同时实现Filter接口。

Java代码  

  1. /**
     * @description 一个自定义的filter,
     *  必须包含authenticationManager,accessDecisionManager,securityMetadataSource三个属性,
            我们的所有控制将在这三个类中实现
     * @author aokunsang
     * @date 2012-8-15
     */
    public class MyFilterSecurityInterceptor extends AbstractSecurityInterceptor
            implements Filter {
    10.
    11.     private FilterInvocationSecurityMetadataSource fisMetadataSource;
    12.
    13.     /* (non-Javadoc)
    14.      * @see org.springframework.security.access.intercept.AbstractSecurityInterceptor#getSecureObjectClass()
    15.      */
    16.     @Override
    17.     public Class<?> getSecureObjectClass() {
    18.         return FilterInvocation.class;
    19.     }
    20.
    21.     @Override
    22.     public SecurityMetadataSource obtainSecurityMetadataSource() {
    23.         return fisMetadataSource;
    24.     }
    25.
    26.     @Override
    27.     public void destroy() {}
    28.
    29.     @Override
    30.     public void doFilter(ServletRequest request, ServletResponse response,
    31.             FilterChain chain) throws IOException, ServletException {
    32.         //super.beforeInvocation(fi);源码
    33.         //1.获取请求资源的权限
    34.             //执行Collection<ConfigAttribute> attributes = SecurityMetadataSource.getAttributes(object);
    35.         //2.是否拥有权限
    36.             //this.accessDecisionManager.decide(authenticated, object, attributes);
    37.         System.out.println("------------MyFilterSecurityInterceptor.doFilter()-----------开始拦截器了....");
    38.         FilterInvocation fi = new FilterInvocation(request, response, chain);
    39.         InterceptorStatusToken token = super.beforeInvocation(fi);
    40.         try {
    41.             fi.getChain().doFilter(fi.getRequest(), fi.getResponse());
    42.         } catch (Exception e) {
    43.             e.printStackTrace();
    44.         }finally{
    45.             super.afterInvocation(token,null);
    46.         }
    47.         System.out.println("------------MyFilterSecurityInterceptor.doFilter()-----------拦截器该方法结束了....");
    48.     }
    49.
    50.     @Override
    51.     public void init(FilterConfig config) throws ServletException {
    52.
    53.     }
    54.
    55.
    56.     public void setFisMetadataSource(
    57.             FilterInvocationSecurityMetadataSource fisMetadataSource) {
    58.         this.fisMetadataSource = fisMetadataSource;
    59.     }
    60. }  

2、FilterInvocationSecurityMetadataSource实现类

Java代码  

  1. /**
     * @description  资源源数据定义,将所有的资源和权限对应关系建立起来,即定义某一资源可以被哪些角色访问
     * @author aokunsang
     * @date 2012-8-15
     */
    public class MySecurityMetadataSource implements FilterInvocationSecurityMetadataSource {  
    
        private UserService userService;
        /* 保存资源和权限的对应关系  key-资源url  value-权限 */
    10.     private Map<String,Collection<ConfigAttribute>> resourceMap = null;
    11.     private AntPathMatcher urlMatcher = new AntPathMatcher();
    12.
    13.     public MySecurityMetadataSource(UserService userService) {
    14.         this.userService = userService;
    15.         loadResourcesDefine();
    16.     }
    17.
    18.     @Override
    19.     public Collection<ConfigAttribute> getAllConfigAttributes() {
    20.         return null;
    21.     }
    22.
    23.     private void loadResourcesDefine(){
    24.         resourceMap = new HashMap<String,Collection<ConfigAttribute>>();
    25. //      Collection<ConfigAttribute> configAttributes1 = new ArrayList<ConfigAttribute>() ;  
    
    26. //      ConfigAttribute configAttribute1 = new SecurityConfig("ROLE_ADMIN");  
    
    27. //      configAttributes1.add(configAttribute1);  
    
    28. //      resourceMap.put("/leftmenu.action", configAttributes1);  
    
    29.
    30.         System.out.println("MySecurityMetadataSource.loadResourcesDefine()--------------开始加载资源列表数据--------");
    31.         List<Role> roles = userService.findAllRoles();
    32.         for(Role role : roles){
    33.             List<Resource> resources = userService.findResourcesByRoleName(role.getName());
    34.             for(Resource resource : resources){
    35.                 Collection<ConfigAttribute> configAttributes = null;
    36.                 ConfigAttribute configAttribute = new SecurityConfig(role.getName());
    37.                 if(resourceMap.containsKey(resource.getUrl())){
    38.                     configAttributes = resourceMap.get(resource.getUrl());
    39.                     configAttributes.add(configAttribute);
    40.                 }else{
    41.                     configAttributes = new ArrayList<ConfigAttribute>() ;
    42.                     configAttributes.add(configAttribute);
    43.                     resourceMap.put(resource.getUrl(), configAttributes);
    44.                 }
    45.             }
    46.         }
    47.     }
    48.     /*
    49.      * 根据请求的资源地址,获取它所拥有的权限
    50.      */
    51.     @Override
    52.     public Collection<ConfigAttribute> getAttributes(Object obj)
    53.             throws IllegalArgumentException {
    54.         //获取请求的url地址
    55.         String url = ((FilterInvocation)obj).getRequestUrl();
    56.         System.out.println("MySecurityMetadataSource:getAttributes()---------------请求地址为:"+url);
    57.         Iterator<String> it = resourceMap.keySet().iterator();
    58.         while(it.hasNext()){
    59.             String _url = it.next();
    60.             if(_url.indexOf("?")!=-1){
    61.                 _url = _url.substring(0, _url.indexOf("?"));
    62.             }
    63.             if(urlMatcher.match(_url,url))
    64.                 return resourceMap.get(_url);
    65.         }
    66.         return null;
    67.     }
    68.
    69.     @Override
    70.     public boolean supports(Class<?> arg0) {
    71.         System.out.println("MySecurityMetadataSource.supports()---------------------");
    72.         return true;
    73.     }
    74.
    75. }  

3、AccessDecisionManager实现类

Java代码  

  1. /**
     * @description  访问决策器,决定某个用户具有的角色,是否有足够的权限去访问某个资源 ;做最终的访问控制决定
     * @author aokunsang
     * @date 2012-8-16
     */
    public class MyAccessDescisionManager implements AccessDecisionManager {  
    
        /**
         * @description 认证用户是否具有权限访问该url地址
    10.      *
    11.      */
    12.     @Override
    13.     public void decide(Authentication authentication, Object obj,
    14.             Collection<ConfigAttribute> configAttributes) throws AccessDeniedException,InsufficientAuthenticationException {
    15.         System.out.println("MyAccessDescisionManager.decide()------------------验证用户是否具有一定的权限--------");
    16.         if(configAttributes==null) return;
    17.         Iterator<ConfigAttribute> it = configAttributes.iterator();
    18.         while(it.hasNext()){
    19.             String needRole = it.next().getAttribute();
    20.             //authentication.getAuthorities()  用户所有的权限
    21.             for(GrantedAuthority ga:authentication.getAuthorities()){
    22.                 if(needRole.equals(ga.getAuthority())){
    23.                     return;
    24.                 }
    25.             }
    26.         }
    27.         throw new AccessDeniedException("--------MyAccessDescisionManager:decide-------权限认证失败!");
    28.     }
    29.
    30.     /**
    31.      * 启动时候被AbstractSecurityInterceptor调用,决定AccessDecisionManager是否可以执行传递ConfigAttribute。
    32.      */
    33.     @Override
    34.     public boolean supports(ConfigAttribute configAttribute) {
    35.         System.out.println("MyAccessDescisionManager.supports()------------角色名:"+configAttribute.getAttribute());
    36.         return true;
    37.     }
    38.
    39.     /**
    40.      * 被安全拦截器实现调用,包含安全拦截器将显示的AccessDecisionManager支持安全对象的类型
    41.      */
    42.     @Override
    43.     public boolean supports(Class<?> clazz) {
    44.         System.out.println("MyAccessDescisionManager.supports()--------------------------------");
    45.         return true;
    46.     }
    47.
    48. }  

补充:还可以实现AuthenticationFailureHandler和AuthenticationSuccessHandler这两个接口,可以做一些验证失败和成功后的业务逻辑操作。(注意实现了这两个接口后,需要手动跳转路径),在<form-login>里面可配置。

4、修改配置文件。

Xml代码  

  1. <?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.1.xsd">  
    
      <http pattern="/resources/**" security="none"></http>
      <http pattern="/user/login" security="none"></http>
    10.
    11.   <http auto-config="true" access-denied-page="/user/denied">
    12.   <!--
    13.     default-target-url       指定了从登录页面登录后进行跳转的页面
    14.     always-use-default-target   true表示登录成功后强制跳转
    15.     authentication-failure-url  表示验证失败后进入的页面
    16.     login-processing-url       设置验证登录验证地址,如果不设置,默认是j_spring_security_check
    17.     username-parameter,password-parameter     设置登录用户名和密码的请求name,默认:j_username,j_password
    18.     default-target-url="/user/home"
    19.    -->
    20.     <form-login login-page="/user/login"
    21.                 always-use-default-target="true"
    22.                 authentication-failure-url="/user/login?error=1"
    23.                 login-processing-url="/logincheck"
    24.                 authentication-success-handler-ref="successHandler"/>
    25.
    26.     <logout logout-url="/logout" logout-success-url="/user/login"/>
    27.     <!--
    28.          error-if-maximum-exceeded 后登陆的账号会挤掉第一次登陆的账号
    29.          session-fixation-protection  防止伪造sessionid攻击,用户登录成功后会销毁用户当前的session。
    30.     -->
    31.     <session-management invalid-session-url="/user/timedout" session-fixation-protection="none">
    32.         <concurrency-control max-sessions="1" error-if-maximum-exceeded="true"/>
    33.     </session-management>
    34.    <custom-filter ref="mySecurityFilter" before="FILTER_SECURITY_INTERCEPTOR"/>
    35.   </http>
    36.
    37.   <authentication-manager alias="authManager">
    38.     <authentication-provider user-service-ref="userServiceDetail">
    39.         <!--<jdbc-user-service data-source-ref="dataSource"
    40.                             authorities-by-username-query=""
    41.                             group-authorities-by-username-query=""/> -->
    42.         <password-encoder hash="md5">
    43.             <salt-source user-property="username"/>   <!-- 盐值  [添加这个属性后,加密密码明文为:"密码明文{盐值}"] -->
    44.         </password-encoder>
    45.
    46.     </authentication-provider>
    47.   </authentication-manager>
    48.
    49.
    50.   <!-- 登录失败后业务处理 -->
    51.   <beans:bean id="failureHandler" class="com.aokunsang.security.LoginAuthenticationFailureHandler"></beans:bean>
    52.   <!-- 登录成功业务处理 -->
    53.   <beans:bean id="successHandler" class="com.aokunsang.security.LoginAuthenticationSuccesssHandler">
    54.     <beans:property name="defaultUrl" value="/user/admin"></beans:property>  <!-- 可变换登录成功后的路径,验证用户是否拥有该权限 -->
    55.   </beans:bean>
    56.
    57.   <!-- 自定义过滤器  -->
    58.   <beans:bean id="mySecurityFilter" class="com.aokunsang.security.MyFilterSecurityInterceptor">
    59.     <beans:property name="accessDecisionManager" ref="accessDescisionManager"></beans:property>
    60.     <beans:property name="fisMetadataSource" ref="securityMetadataSource"></beans:property>
    61.     <beans:property name="authenticationManager" ref="authManager"></beans:property>
    62.   </beans:bean>
    63.
    64.   <beans:bean id="securityMetadataSource" class="com.aokunsang.security.MySecurityMetadataSource">
    65.     <beans:constructor-arg name="userService" ref="userService"></beans:constructor-arg>
    66.   </beans:bean>
    67.
    68.   <beans:bean id="accessDescisionManager" class="com.aokunsang.security.MyAccessDescisionManager"></beans:bean>
    69.
    70.   <beans:bean id="userServiceDetail" class="com.aokunsang.security.MyUserDetailServiceImpl">
    71.     <beans:property name="userService">
    72.         <beans:ref bean="userService"/>
    73.     </beans:property>
    74.   </beans:bean>
    75. </beans:beans>
    

4.3.替换form-login配置,实现自己的业务逻辑

如果想在登录之前做一些业务逻辑操作,比如:检查验证码的正确性(这个操作肯定要在验证用户名密码之前操作了)。那么我们自己继承UsernamePasswordAuthenticationFilter类,替换form-login里面的配置,完成检查验证码的操作;这里还需要注意一点,我们还需要实现一个未登录的切点(配置AuthenticationProcessingFilterEntryPoint或者LoginUrlAuthenticationEntryPoint),也就是没登录的都跳转到这个页面,相当于<form-login>中的login-page属性。

这里面的配置注意两点就行:

1、在<http>中添加未登录切点配置entry-point-ref属性;

2、去掉<form-login>,添加<custom-filter ref="XXXXFilter" position="FORM_LOGIN_FILTER"/>

说明:详细使用方法以及用户账户登录数控制<session-management><concurrency-control></session-management>可参考另一博客http://aokunsang.iteye.com/blog/1944111

http://blog.csdn.net/k10509806/article/details/6436987

http://hi.baidu.com/youxitou/item/de0fb00e76e15095a2df43cd

4.4.补充问题汇总

在项目中使用spring Security3.1时,发现抛出的UsernameNotFoundException异常信息,总是打印出Bad credentials。如果我想得到比如:用户不存在,等信息,需要在xml中做设置。

Xml代码  

  1. <!-- 使用该类主要解决例如UsernameNotFoundException抛出的异常全部显示Bad credentials[详细参考AbstractUserDetailsAuthenticationProvider:authenticate()];
                 注意:如果通过用户名已经查询到用户信息(密码错误),此时抛出异常依然为Bad credentials[详细参考DaoAuthenticationProvider:additionalAuthenticationChecks()]
       -->
      <beans:bean id="daoAuthenticationProvider" class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
        <beans:property name="userDetailsService" ref="userServiceDetail"></beans:property>
        <beans:property name="passwordEncoder" ref="md5Encoder"></beans:property>
        <beans:property name="hideUserNotFoundExceptions" value="false"/><!-- 【关键】没有这个将不能准确地报告异常(全部报告异常为:Bad credentials) -->
       </beans:bean>  
    
    10.   <beans:bean id="md5Encoder" class="org.springframework.security.authentication.encoding.Md5PasswordEncoder"></beans:bean>
    11.
    12.   <authentication-manager alias="authManager">
    13.     <authentication-provider ref="daoAuthenticationProvider"></authentication-provider>
    14.   </authentication-manager>
    15.     

5.附录

5.1.默认请求参数说明


默认值


说明


可设置


j_username


请求用户名


<from_login/>中

username_parameter

属性


j_password


请求密码


<from_login/>中

password_parameter

属性


j_spring_security_check


Post请求验证路径


<from_login/>中

login_processing_url属性


_spring_security_remember_me


“记住我”的请求name


暂无


sessionScope[‘SPRING_SECURITY_LAST_USERNAME‘]


Session中保存的最后一次登录的用户名


暂无

时间: 2024-11-04 05:55:46

Spring-Security完整实例的相关文章

spring security 应用实例

开篇说明 最近工作有权限控制的需求,所以看了一下spring的security,它提供了很好的安全服务: 参考文章:http://peiquan.blog.51cto.com/7518552/1384168 ; 在这里我使用第三种权限控制方法,即将用户,权限,资源使用数据库存储,并自定义过滤器,在配置文件里进行相应配置. 二.数据准备 --权限表 CREATE TABLE `authorities` (  `id` int(11) NOT NULL AUTO_INCREMENT,  `autho

Spring Security 配置实例

这几天学习了一下Spring Security3.1,从官网下载了Spring Security3.1版别进行操练,通过屡次测验才摸清了其间的一些原理.自己不才,希望能协助大家.还有,这次我第2次写博客啊,文体不是很行.希望能让观看者不发生疲乏的感受,我现已心满意足了.一.数据库构造     先来看一下数据库构造,选用的是根据人物-资本-用户的权限办理规划.(MySql数据库)    为了节约华章,只对对比重要的字段进行注释.    1.用户表Users    CREATE TABLE `use

Spring Security 3.x 完整入门教程

Spring Security 3.x 出来一段时间了,跟Acegi是大不同了,与2.x的版本也有一些小小的区别,网上有一些文档,也有人翻译Spring Security 3.x的guide,但通过阅读guide,无法马上就能很容易的实现一个完整的实例. 我花了点儿时间,根据以前的实战经验,整理了一份完整的入门教程,供需要的朋友们参考. 1,建一个web project,并导入所有需要的lib,这步就不多讲了. 2,配置web.xml,使用Spring的机制装载: <?xml version=&qu

spring mvc 和ajax异步交互完整实例(转自CSDN) 附下载地址

spring mvc 和ajax异步交互完整实例 spring MVC 异步交互demo: demo下载地址:http://download.csdn.net/download/quincylk/9521375 1.jsp页面: [java] view plain copy print? <%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-

Spring和ActiveMQ整合的完整实例

Spring和ActiveMQ整合的完整实例 前言 这篇博文,我们基于Spring+JMS+ActiveMQ+Tomcat,做一个Spring4.1.0和ActiveMQ5.11.1整合实例,实现了Point-To-Point的异步队列消息和PUB/SUB(发布/订阅)模型,简单实例,不包含任何业务. 环境准备 工具 JDK1.6或1.7 Spring4.1.0 ActiveMQ5.11.1 Tomcat7.x 目录结构 所需jar包 项目的配置 配置ConnectionFactory conn

Spring MVC4 + Spring Security4 + Hibernate实例

http://www.yiibai.com/spring-security/spring-mvc-4-and-spring-security-4-integration-example.html 在这篇教程文章中,我们将使用Spring Security,Hibernate+MySQL数据库来集成构建一个成熟的Spring MVC应用程序.处理多对多映射关系,同时利用BCrypt格式加密密码存储,和使用自定义PersistentTokenRepository实现Hibernate Hiberna

Spring Security OAuth2 开发指南。

官方原文:http://projects.spring.io/spring-security-oauth/docs/oauth2.html 翻译及修改补充:Alex Liao. Spring OAuth2.0 提供者实现原理: Spring OAuth2.0提供者实际上分为: 授权服务 Authorization Service. 资源服务 Resource Service. 虽然这两个提供者有时候可能存在同一个应用程序中,但在Spring Security OAuth中你可以把 他它们各自放在

[转]Spring Security学习总结一

[总结-含源码]Spring Security学习总结一(补命名空间配置) Posted on 2008-08-20 10:25 tangtb 阅读(43111) 评论(27)  编辑  收藏 所属分类: Spring .Spring Security Spring Security学习总结一 在认识Spring Security之前,所有的权限验证逻辑都混杂在业务逻辑中,用户的每个操作以前可能都需要对用户是否有进行该项 操作的权限进行判断,来达到认证授权的目的.类似这样的权限验证逻辑代码被分散

Spring Security 入门(1-14)Spring Security 开发指南(转)

开发指南:http://www.cnblogs.com/xingxueliao/p/5911292.html Spring OAuth2.0 提供者实现原理: Spring OAuth2.0提供者实际上分为: 授权服务 Authorization Service. 资源服务 Resource Service. 虽然这两个提供者有时候可能存在同一个应用程序中,但在Spring Security OAuth中你可以把 他它们各自放在不同的应用上,而且你可以有多个资源服务,它们共享同一个中央授权服 务

Spring Security学习总结

1.Spring Security介绍  一般来说,Web 应用的安全性包括用户认证(Authentication)和用户授权(Authorization)两个部分. 用户认证指的是验证某个用户是否为系统中的合法主体,也就是说用户能否访问该系统.用户认证一般要求用户提供用户名和密码.系统通过校验用户名和密码来完成认证过程. 用户授权指的是验证某个用户是否有权限执行某个操作.在一个系统中,不同用户所具有的权限是不同的.比如对一个文件来说,有的用户只能进行读取,而有的用户可以进行修改.一般来说,系统