使用spring安全容器管理web程序

来源:互联网 发布:浙江理工大学校长 知乎 编辑:程序博客网 时间:2024/05/29 04:46

说明.ssh的不贴了 只有spring安全容器的 其他的不贴(目标 实现简单的管理)

spring的容器好处微笑:解决session伪造 跳跃访问 页面必须参数 方法权限等等

 数据库  :基本的 用户表-资源表-角色表及相互之间的关联表

 

web.xml

   <!-- spring的监听 -->
  <listener>
     <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>
 
   <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> 

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:p="http://www.springframework.org/schema/p"
 xmlns:security="http://www.springframework.org/schema/security"
 xsi:schemaLocation="http://www.springframework.org/schema/beans
 http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
  http://www.springframework.org/schema/security
    http://www.springframework.org/schema/security/spring-security-3.1.xsd
 ">
 
   <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
   <property name="driverClass" value="com.microsoft.sqlserver.jdbc.SQLServerDriver">
   </property>
   <property name="jdbcUrl" value="jdbc:sqlserver://localhost:1433;databaseName=mydb">
   </property>
   <property name="user" value="sa"></property>
   <property name="password" value="123456"></property>
    </bean>
 

<!--不用添加到安全容器中去-->
  <security:http pattern="/**/*.css" security="none"/>
  <security:http pattern="/login.jsp*" security="none"/>
  <security:http pattern="/admin/login.jsp*" security="none"/>
    
  <security:http  access-decision-manager-ref="myaccessDecisionManager">
       <!-- 没用但是重要 否者不会执行我们自定义的myaccessDecisionManager-->
       <security:intercept-url pattern="/**" access="ROLE_XXX" />
        <!-- session失效去的页面,  -->
        <security:session-management invalid-session-url="/login.jsp"></security:session-management>
        <!-- 登录页面为/login.jsp,登录成功页面为/index.jsp,且总是用这个页面为登录成功页面 -->
        <security:form-login login-page="/login.jsp" authentication-failure-url="/login.jsp" default-target-url="/index.jsp"  always-use-default-target="true"  />
 </security:http>
  <bean id="myaccessDecisionManager" class="com.spring.MyAccessDecisionManager">
     <property name="dataSource" ref="dataSource"></property>
  </bean>
 
 <security:authentication-manager>
        <security:authentication-provider> 
        <!-- 查询用户和对应的权限。。 -->
        <security:jdbc-user-service data-source-ref="dataSource" 
        users-by-username-query="select u.username,u.password,u.status as enabled from users u where u.username=? " 
         authorities-by-username-query="select u.username, r.name as authority from dbo.user_role ur join dbo.users u
         on u.id=ur.user_id join dbo.roles r on r.id=ur.role_id where u.username = ? "  cache-ref="userCache"/>
      </security:authentication-provider>
 </security:authentication-manager>
 <!--用户的缓存-->
 <bean id="userCache" class="org.springframework.security.core.userdetails.cache.EhCacheBasedUserCache">
       <property name="cache" ref="userEhCache"></property>
  </bean>   
  <bean id="userEhCache" class="org.springframework.cache.ehcache.EhCacheFactoryBean">
      <property name="cacheManager" ref="cacheManager"></property>
      <property name="cacheName" value="userCache"></property>
  </bean>
  <bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"></bean>
    
 
  <!-- 消息提示 -->
  <bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
        <property name="basename" value="classpath:org/springframework/security/messages_zh_CN" />
    </bean>
 

</beans>

上面的可以添加更多的东西  请参考官方的文档

 

自己定义的MyAccessDecisionManager类

package com.spring;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;

import org.apache.log4j.Logger;
import org.springframework.jdbc.core.support.JdbcDaoSupport;
import org.springframework.security.access.AccessDecisionManager;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.access.AuthorizationServiceException;
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.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;

import com.mchange.v2.c3p0.ComboPooledDataSource;

public class MyAccessDecisionManager  implements AccessDecisionManager{

 private  Logger logger = Logger.getLogger(MyAccessDecisionManager.class);
 
 private ComboPooledDataSource  dataSource; 
 public ComboPooledDataSource getDataSource() {
  return dataSource;
 }
 public void setDataSource(ComboPooledDataSource dataSource) {
  this.dataSource = dataSource;
 }
  
 @Override
 public void decide(Authentication authentication, Object object,
   Collection<ConfigAttribute> configAttributes) throws AccessDeniedException,
   InsufficientAuthenticationException {
  

//请求的url
  logger.info("当前请求:"+object.toString() ); 
   Object obj = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
   UserDetails userDetails = null;
   List<String> list_role= null;
   //没有当前用户  --》跳跃访问
   try {
    userDetails =(UserDetails)obj;
  } catch (Exception e) {
    throw new AuthorizationServiceException("认证失败!");
  }
   Connection con =null;
   PreparedStatement ps  = null;
   ResultSet set  = null;
   try {
   con= dataSource.getConnection();
    String sql = "select rl.name from resc_role rr join rescs re on rr.resc_id = re.id  join roles rl on rr.role_id = rl.id where re.res_string = ? ";
   //数据库查询对应的
    ps=  con.prepareStatement(sql);
    System.out.println( "|"+ object.toString().substring( object.toString().indexOf("/")  )+"|" );
    ps.setString(1 ,  object.toString().substring( object.toString().indexOf("/")  )  );
    set =  ps.executeQuery(); 
    list_role = new ArrayList<String>();
    while(set.next()){   
     list_role.add(set.getString("name") );
    }
  } catch (Exception e) {
   // TODO: handle exception
   e.printStackTrace();
  }finally{
  
    try {
     if(set!=null)set.close();
    } catch (SQLException e) {
     // TODO Auto-generated catch block
     e.printStackTrace();
    }
    try {
     if(set!=null) ps.close();
    } catch (SQLException e) {
     // TODO Auto-generated catch block
     e.printStackTrace();
    }
    try {
     if(set!=null) con.close();
    } catch (SQLException e) {
     // TODO Auto-generated catch block
     e.printStackTrace();
    } 
  } 
  
  for (String string : list_role) {
   //当前用户角色
   for( GrantedAuthority g : userDetails.getAuthorities()){
     if( g.getAuthority() .equals(string) ){
      logger.info("您有权限!");
      return;
     }
    }
  }
     throw new AccessDeniedException("呵呵!没有权限!");  
 }

 @Override
 public boolean supports(ConfigAttribute arg0) {
  // TODO Auto-generated method stub
  return true;//fan hui true
 }

 @Override
 public boolean supports(Class<?> arg0) {
  // TODO Auto-generated method stub
  return true;//fanhui false
 }

 
}
类说明: 其实可以使用hibernate的缓存解决查询问题 该类可以拿到请求的路径和当前用户相互判断 如果没有抛出没权限的异常 自己看来很多的文档觉得这个简单官方也推荐 最好不要改源码

bug:我个人没搞出来的就是使用两个登录的页面登录 现实中的肯定有的 我配置两个登录页面错误之后都跳到同一个页面 如果你解决了联系哦 

 

参考

spring 3.1安全容器官方文档

 

 

原创粉丝点击